2

我正在编写一个程序,它有两个主要阶段:确定感兴趣的区域,然后识别该区域中的对象。我的界面有一个 JProgressBar,我希望它指示它当前处于哪个阶段。我注意到,使用简单的“线性”方法,只会显示第二条消息。因此,在https://stackoverflow.com/a/277048之后,我使用 Runnables 和 SwingUtilities.invokeLater 来设置我的进度条的字符串。

private class MarkListener implements ActionListener {
    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.execute();

        RecognitionTask rt = new RecognitionTask();
        rt.addPropertyChangeListener(PrismRunnable.this);

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

        rt.execute();
    }
}

但是,这不起作用——只有“分段”保留在进度条的文本中。

我已经尝试过使用 EventQueue 而不是 SwingUtilities 但无济于事。那么,我该怎么做呢?

4

1 回答 1

4

您必须了解,在调用之间没有(也不应该有)代码暂停

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

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

除了第一位代码完成和到达第二位代码所需的毫秒数之外,两个后台任务很可能同时发生。

解决此问题的选项包括:

  • 使用两个 JProgressBar,每个任务一个,
  • 或从单个 SwingWorker 中运行这两个任务,以便两者都可以在同一个后台线程中完成并按顺序运行,
  • 或在第一个任务的属性更改侦听器通知您第一个任务已完成(状态属性返回 SwingWorker.StateValue.DONE)之后运行第二个任务。

例如,

  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();
  }

编辑:
请注意,不需要JProgressBar#setString(...)在事件线程上对方法进行排队,因为上面的所有代码都已经事件线程中,即 EDT。仅当当前代码从 EDT 中被调用时,或者在其他一些特殊情况下(这不是其中之一),才需要这样做。

所以你的代码看起来像这样会更好:

     // ** 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();
              }
于 2012-03-14T20:01:14.827 回答