从runnable更新GUI

时间:2012-04-28 16:29:23

标签: java swing user-interface concurrency event-dispatch-thread

我正在构建一个Swing应用程序,其中一部分功能应该是直观地和可听地处理和输出一些文本(使用Mary TTS)。我需要一些关于GUI和文本处理类进行通信的最佳方法的建议。

GUI类是JPanel的子类。在其中我有一个实现Runnable的类,名为LineProcesser,它准备将文本分派给音频播放器。我正在使用一个线程执行器来阻止它离开EDT(这可能不是最好的方式,但它似乎达到了我所追求的结果)。

我的目的是让LineProcessor运行所有文本并在每行末尾更新JTextArea。此外,它需要停止并等待某些点的用户输入。用户输入完成后,GUI类应该告诉它继续处理。

以下代码说明了我目前的情况:

public class MyPanel extends JPanel {
    ExecutorService lineExecutor = Executors.newSingleThreadExecutor();
    Runnable lineProcessor = new LineProcessor();

    public class LineProcessor implements Runnable {

        private int currentLineNo = 0;

            public LineProcessor() {
            //  ...
            }

            @Override
            public void run() {
                // call getText();  
                // call playAudio();
                currentLineNo++;
            }
        }
    }

    private JButton statusLbl = new JLabel();       
    private JButton mainControlBtn = new JButton();

    private void mainControlBtnActionPerformed(ActionEvent evt) {

        if (mainControlBtn.getText().equals("Start")) {
                          lineExecutor.submit(lineProcessor);
                          mainControlBtn.setText("Running");
        }
    }
}

LineProcessor如何通知他们需要更改的GUI组件以及如何在GUI中暂停和重新启动它们?我对是否需要Swing Worker,属性/事件监听器或其他东西感到困惑?我读过的例子很有意义,但我看不出如何将它们应用到我这里的代码中。

3 个答案:

答案 0 :(得分:6)

您需要做的就是在Runnable中包装任何Swing调用,并通过SwingUtilities.invokeLater(myRunnable);在EDT上对其进行排队。而已。不需要SwingWorker。

例如,

public class LineProcessor implements Runnable {
  private int currentLineNo = 0;
  Runnable LineProcessor = new LineProcessor();  // won't this cause infinite recursion?

  public LineProcessor() {
     // ...
  }

  @Override
  public void run() {
     // call getText();
     // call playAudio();
     currentLineNo++;

     SwingUtilities.invokeLater(new Runnable() {
        public void run() {
           // *** Swing code can go here ***
        }
     });
  }
}

答案 1 :(得分:3)

您必须同时使用SwingWorker和事件方法。

  1. 将长时间运行的代码放在Swing Worker中。
  2. 创建新的属性更改事件,侦听器,管理器
  3. 在SwingWorker中,当发生更改事件时,请调用PropertyChangeManager以通知所有liseners。
  4. 所有想要通过事件通知的GUI组件都应该使用PropertyChangeManager注册自己。
  5. 您的PropertyChangeManager将调用PropertyChangeListener的customProperyChange方法并传递properyChangeEvent

答案 2 :(得分:3)

您要找的是SwingWorker。这个类允许在工作线程上执行工作,在EDT上定期更新,最后也更新EDT。

有关SO和Swing教程的几个示例。只需几个链接

可以使用publish方法完成报告进度,这些结果将传递到您可以更新UI的process方法。最后,调用done方法,允许您执行一些最终的UI更新。

对于暂停/重启功能...您可以使用invokeAndWait方法中的doInBackground使用阻止方法调用(例如,显示要求用户输入的JOptionPane)。但是如果你开始在invokeAndWait中使用doInBackground,使用SwingWorker可能会有点过分,你可以选择@Hovercraft Full Of Eels建议