2016-04-12 14 views
0

Ich arbeite derzeit an einer kleinen Anwendung zum Anzeigen/Speichern von Notizen. Der Inhalt jeder Notiz wird nach dem Schließen der Anwendung in einer .properties-Datei auf meiner Festplatte gespeichert. Wenn Sie die Anwendung erneut öffnen, werden alle Notizen in der Anwendung geladen.Java SwingWorker jetzt zu aktualisieren Modell

Während dieser Ladevorgang wird ein Dialogfeld mit einer Fortschrittsleiste angezeigt, die den Status des Prozesses angibt. Außerdem zeige ich eine GlassPane an, damit der Benutzer nicht mit der GUI interagieren oder Notizen während des Ladevorgangs speichern kann.

Es folgt mein aktueller-Code für das Laden der Noten:

public void load() { 

    new Thread() { 
     @Override 
     public void run() { 
      Properties data = new Properties(); 
      FileInputStream iStream = null; 
      File[] files = sortPairs(); 
      int fileIndex = -1; 

      SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        pnlGlass = new MyGlassPane(); 
        infoText = new JTextField(); 
        progBar = new JProgressBar(0,100); 
        progBar.setValue(0); 
        progBar.setStringPainted(true); 
        infoBox = new LoadInfoDialog(infoText,progBar); 
        infoBox.setLocationRelativeTo(gui); 
        infoBox.setVisible(true); 
        infoBox.setDefaultCloseOperation(infoBox.DO_NOTHING_ON_CLOSE); 
        pnlGlass.setOpaque(false); 
        pnlGlass.addMouseListener(new MouseAdapter() { 
         @Override 
         public void mousePressed(MouseEvent me) { 
          me.consume(); 
         } 
        }); 
        gui.setGlassPane(pnlGlass); 
        pnlGlass.setVisible(true); 
        pnlGlass.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
       } 

      }); 
      for (File file : files) { 
       if (file.isFile()) { 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e1) { 
         // TODO Auto-generated catch block 
         e1.printStackTrace(); 
        } 
        try { 
         iStream = new FileInputStream(file); 
         data.load(iStream); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } finally { 
         if (!(iStream == null)) { 
          try { 
           iStream.close(); 
          } catch (IOException e) { 
           e.printStackTrace(); 
          } 
         } 
        } 
        String title = data.getProperty("title"); 
        String text = data.getProperty("text"); 
        String erstellt = data.getProperty("date"); 
        String fileName = data.getProperty("filename"); 
        Note note = new Note(text, title); 
        note.setFileName(fileName); 
        note.setDate(erstellt); 
        fileIndex++; 
        final int fileIndexFinal = fileIndex; 
        SwingUtilities.invokeLater(new Runnable() { 

         @Override 
         public void run() { 
          progBar.setValue(progBar.getValue() + 100/fileCount); 


          infoText.setText("Lade Notizen, bitte warten..." + progBar.getValue() + "%"); 
          noteModel.addNote(note); 
          System.out.println("Index:" + fileIndexFinal); 
         } 

        }); 

       } 
      } 
      SwingUtilities.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        pnlGlass.setVisible(false); 
        infoBox.setVisible(false); 

       } 
      }); 
     } 
    }.start(); 

} 

Ich bin sicher, dass meine Lösung ziemlich zackig ist. Nach einigen Nachforschungen stellte ich fest, dass es genau zu diesem Zweck eine Klasse namens "SwingWorker" gibt (Taks im Hintergrund laufen lassen und GUI aktualisieren) ABER, wie kann ich meine Notiz aus dem SwingWorker heraus erstellen (Note-Object zu meinem Model hinzufügen)?

Ich weiß, dass ich meine Fortschrittsleiste mit den Veröffentlichungs- und Prozessmethoden aktualisieren kann, aber wie kann ich ein Objekt mit dem SwingWorker erstellen?

Der Ladevorgang sollte für jede Note die folgende Routine tun:

lesen Inhalt von .properties-Datei -> erstellen note Object -> show note in JList -> update progressbar.

+0

Verwenden Sie 'publish' /' process', um die geladene Notiz zu "publizieren", verwenden Sie einen 'PropertyChangeListener' nicht Monitor für den Fortschritt – MadProgrammer

+0

Bitte siehe [Swing Worker Trail] (https://docs.oracle.com/javase/tutorial/ uiswing/concurrency/simple.html) – Sanjeev

Antwort

1

Beginnen Sie mit Ihrem Kern Arbeiter definieren ...

public class NotesLoader extends SwingWorker<List<Properties>, Properties> { 

    @Override 
    protected List<Properties> doInBackground() throws Exception { 
     List<Properties> notes = new ArrayList<>(25); 
     File[] files = new File(".").listFiles(new FilenameFilter() { 
      @Override 
      public boolean accept(File dir, String name) { 
       return name.toLowerCase().endsWith(".properties"); 
      } 
     }); 

     for (File file : files) { 
      int count = 0; 
      try (Reader reader = new FileReader(file)) { 
       Properties note = new Properties(); 
       note.load(reader); 

       notes.add(note); 
       publish(note); 
       setProgress((int) ((count/(double) files.length) * 100d)); 
      } 
     } 

     return notes; 
    } 

} 

Diese einfache Scans den Strom für .properties Dateien Arbeitsverzeichnis und versucht, sie einer nach dem anderen zu laden. Wenn einer geladen ist, wird er über die Methode publish gesendet und der Fortschritt wird über die Methode setProgress aktualisiert.

Nun entwickelt ich eine einfache Fortschrittsanzeige, die wie folgt aussieht ...

public class LoadingPane extends JPanel { 

    private JLabel label; 
    private JProgressBar pb; 

    public LoadingPane() { 
     setLayout(new GridBagLayout()); 
     setOpaque(false); 

     label = new JLabel("Loading, please wait"); 
     pb = new JProgressBar(); 

     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.gridwidth = GridBagConstraints.REMAINDER; 
     add(label, gbc); 
     add(pb, gbc); 

     addMouseListener(new MouseAdapter() { 
     }); 
     setFocusable(true); 
    } 

    public void setProgress(float progress) { 
     pb.setValue((int) (progress * 100f)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g.create(); 
     g2d.setColor(new Color(128, 128, 128, 128)); 
     g2d.fillRect(0, 0, getWidth(), getHeight()); 
     g2d.dispose(); 
    } 

} 

Dies ist wichtig, da es eine setProgress Methode

Jetzt hat, können wir diese beiden zusammen verwenden zu laden die Notizen im Hintergrund und aktualisieren Sie die Benutzeroberfläche sicher, während der Fortschritt aktualisiert wird.

LoadingPane loadingPane = new LoadingPane(); 
JFrame frame = new JFrame("Testing"); 
frame.setGlassPane(loadingPane); 
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
frame.add(new JLabel("I'll wait here okay")); 
frame.pack(); 
frame.setLocationRelativeTo(null); 
frame.setVisible(true); 

NotesLoader loader = new NotesLoader() { 
    @Override 
    protected void process(List<Properties> chunks) { 
     System.out.println(chunks.size() + " notes were loaded"); 
     // Update you model?? 
    } 
}; 
loader.addPropertyChangeListener(new PropertyChangeListener() { 
    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     String name = evt.getPropertyName(); 
     switch (name) { 
      case "state": 
       switch (loader.getState()) { 
        case STARTED: 
         frame.getGlassPane().setVisible(true); 
         frame.getGlassPane().requestFocusInWindow(); 
         break; 
        case DONE: 
         frame.getGlassPane().setVisible(false); 
         try { 
          // Doubt your need the list, but it's good to do this 
          // incase there was an exception which occured during 
          // the running of the worker 
          List<Properties> notes = loader.get(); 
         } catch (InterruptedException | ExecutionException ex) { 
          ex.printStackTrace(); 
          // Maybe show an error message... 
         } 
         break; 
       } 
       break; 
      case "progress": 
       // I like working with normalised values :P 
       loadingPane.setProgress(((int)evt.getNewValue()/100f)); 
       break; 
     } 
    } 
}); 

Das Beispiel überschreibt die process Methode, so dass Sie die Noten bekommen, wie sie geladen werden, aber ebenso könnte man bis in die Zustandsänderungen zu DONE warten und sie alle auf einmal bekommen, dann ist es an Ihnen

+0

Danke für Ihre Hilfe MP. Ich habe gerade erst vor 2 Monaten angefangen zu schreiben, also gibt es viele Fragezeichen, sogar nach dem Lesen der API-Dokumentation. Aber dein Beispiel ist ziemlich gut und ich denke, ich bekomme es jetzt. – Corovus

+0

Eine weitere Frage tho. Warum teilst und multiplizierst du den Fortschritt mit 100? – Corovus

+0

Da ich gerne in einem normalisierten Fortschritts-Wert arbeite (0-1), habe ich eine Menge Code basierend auf diesem Konzept, aber Java arbeitet gerne in 1-100 – MadProgrammer

Verwandte Themen