简体   繁体   English

从runnable更新GUI

[英]Updating GUI from a runnable

I'm building a Swing application and one part of the functionality should be to process and output some text visually and audibly (using Mary TTS). 我正在构建一个Swing应用程序,其中一部分功能应该是直观地和可听地处理和输出一些文本(使用Mary TTS)。 I need some advice on the best way for the GUI and text processing classes to communicate. 我需要一些关于GUI和文本处理类进行通信的最佳方法的建议。

The GUI class is a subclass of JPanel. GUI类是JPanel的子类。 Within that I have a class implementing Runnable, called LineProcesser, which prepares the text to be dispatched to an audio player. 在其中我有一个实现Runnable的类,名为LineProcesser,它准备将文本分派给音频播放器。 I'm using a thread executor to keep this off the EDT (that may not be the best way but it seems to achieve the result I'm after). 我正在使用一个线程执行器来阻止它离开EDT(这可能不是最好的方式,但它似乎达到了我所追求的结果)。

My intention is for LineProcessor to run through all the text and update a JTextArea at the end of each line. 我的目的是让LineProcessor运行所有文本并在每行的末尾更新JTextArea。 Additionally it will need to halt and wait for user input at certain points. 此外,它需要停止并等待某些点的用户输入。 After the user input has been completed the GUI class should tell it to resume processing. 用户输入完成后,GUI类应该告诉它继续处理。

The following code illustrates what I currently have: 以下代码说明了我目前拥有的内容:

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

How can LineProcessor notify GUI components that they need to change and how can it be paused and restarted from within the GUI? LineProcessor如何通知他们需要更改的GUI组件以及如何从GUI中暂停和重新启动它们? I'm confused as to whether I need a Swing Worker, property/event listeners or something else? 我对是否需要Swing Worker,属性/事件监听器或其他东西感到困惑? The examples I've read sort of make sense but I can't see how I can apply them to the code I have here. 我读过的例子很有意义,但我看不出如何将它们应用到我这里的代码中。

All you need to do is wrap any Swing calls in a Runnable, and queue it on the EDT via SwingUtilities.invokeLater(myRunnable); 您需要做的就是在Runnable中包装任何Swing调用,并通过SwingUtilities.invokeLater(myRunnable);将其排在EDT上SwingUtilities.invokeLater(myRunnable); . That's it. 而已。 No need for a SwingWorker. 不需要SwingWorker。

eg, 例如,

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

You will have to use both SwingWorker and Event methodology. 您必须同时使用SwingWorker和Event方法。

  1. Place your long running code in Swing Worker. 将长时间运行的代码放在Swing Worker中。
  2. Create new property change Event, listener, manager 创建新的属性更改事件,侦听器,管理器
  3. In your SwingWorker, when the change event occurs, call PropertyChangeManager to notify all the liseners. 在SwingWorker中,当发生更改事件时,请调用PropertyChangeManager以通知所有liseners。
  4. All GUI components which wants to be notified with the event should register themselves with the PropertyChangeManager. 想要通过事件通知的所有GUI组件都应该使用PropertyChangeManager注册自己。
  5. Your PropertyChangeManager will call customProperyChange method of the PropertyChangeListener and will pass the properyChangeEvent 您的PropertyChangeManager将调用PropertyChangeListener的customProperyChange方法并将传递properyChangeEvent

What you are looking for is a SwingWorker . 您正在寻找的是SwingWorker This class allows to perform the work on a worker thread, having periodical updates on the EDT, and in the end update the EDT as well. 该类允许在工作线程上执行工作,在EDT上定期更新,最后也更新EDT。

Several examples are available on SO and in the Swing tutorials. 有关SO和Swing教程的几个示例。 Just a few links 只是几个链接

Reporting progress can be done with the publish method, these results will be passed to the process method in which you can update the UI. 可以使用publish方法完成报告进度,这些结果将传递给您可以更新UI的process方法。 At the end, the done method is called allowing you to perform some final UI updates. 最后,调用done方法,允许您执行一些最终的UI更新。

For the pause/restart functionality ... you can use an invokeAndWait in the doInBackground method with a blocking method call (for example showing a JOptionPane asking for user input). 对于暂停/重启功能...您可以在doInBackground方法中使用invokeAndWait和阻塞方法调用(例如,显示要求用户输入的JOptionPane )。 But if you start using invokeAndWait in the doInBackground it might be overkill to use the SwingWorker and you can simply opt for the approach @Hovercraft Full Of Eels suggested 但是如果你开始在doInBackground使用invokeAndWait ,使用SwingWorker可能会doInBackground过分,你可以简单地选择@Hovercraft Full Of Eels建议的方法

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM