2012-03-14 2 views
2

J'écris un programme qui comporte deux phases principales: la détermination de la région d'intérêt, puis la reconnaissance des objets dans cette région. Mon interface a un seul JProgressBar et je veux qu'il indique sur quelle phase il travaille actuellement. J'ai remarqué qu'avec une approche "linéaire" simple, seul le deuxième message est affiché. Donc, suivant https://stackoverflow.com/a/277048, j'utilise Runnables et SwingUtilities.invokeLater pour définir la chaîne de ma barre de progression. Cependant, cela ne fonctionne pas --- seul le "segment" reste dans le texte de la barre de progression.setString d'un JProgressBar plusieurs fois

J'ai déjà essayé d'utiliser EventQueue au lieu de SwingUtilities, mais en vain. Alors, comment je vais faire ça?

Répondre

4

Vous devez comprendre qu'il n'y a pas de pause dans le code (ne devrait y avoir) entre votre appel à

recognitionProgress.setString("Marking ROI..."); 

et

recognitionProgress.setString("Segmenting..."); 

sauf pour les millisecondes requises pour le premier bit du code pour compléter et atteindre le second bit de code, et les deux tâches d'arrière-plan se produisent probablement simultanément.

options pour résoudre ce comprennent:

  • En utilisant deux JProgressBars, une pour chaque tâche,
  • ou l'exécution des deux tâches à partir d'un seul SwingWorker de sorte que les deux peuvent se faire dans le même thread d'arrière-plan et l'exécution séquentiellement,
  • ou l'exécution de la deuxième tâche après que l'écouteur de modification de propriété de la première tâche vous informe que la première tâche a été achevée (la propriété d'état renvoie SwingWorker.StateValue.DONE).

par exemple,

public void actionPerformed(ActionEvent ae) { 
    mainFrame.getGlassPane().setCursor(new Cursor(Cursor.WAIT_CURSOR)); 
    recognitionProgress.setStringPainted(true); 
    BlueMarkerTask bmt = new BlueMarkerTask(); 
    bmt.addPropertyChangeListener(PrismRunnable.this); 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      recognitionProgress.setString("Marking ROI..."); 
     } 
    }); 

    bmt.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (pcEvt.getPropertyName().equals("state")) { 
       if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) { 
       // you'd probably have this in a method. 
       RecognitionTask rt = new RecognitionTask(); 
       rt.addPropertyChangeListener(PrismRunnable.this); 

       SwingUtilities.invokeLater(new Runnable() { 
        public void run() { 
         recognitionProgress.setString("Segmenting..."); 
        } 
       }); 

       rt.execute(); 
       } 
      } 
     } 
    }); 

    bmt.execute(); 
    } 

Edit:
Notez qu'il n'y a pas besoin de faire la queue la méthode JProgressBar#setString(...) sur le fil des événements, puisque tout le code ci-dessus est déjà dans le fil des événements , l'EDT. Ceci n'est nécessaire que lorsque le code actuel est annulé de l'EDT, ou dans quelques autres situations particulières (ce n'est pas l'un d'entre eux).

Donc, votre code serait mieux ressembler à ceci:

 // ** no need to queue this on the event thread. 
    // ** we're already IN the event thread! 
    recognitionProgress.setString("Marking ROI..."); 

    bmt.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (pcEvt.getPropertyName().equals("state")) { 
       if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) { 
       // you'd probably have this in a method. 
       RecognitionTask rt = new RecognitionTask(); 
       rt.addPropertyChangeListener(PrismRunnable.this); 

       // ** no need to queue this on the event thread. 
       // ** we're already IN the event thread! 
       recognitionProgress.setString("Segmenting..."); 

       rt.execute(); 
       }