Swing invokeandwait

时间:2014-02-05 22:43:44

标签: swing events user-interface

我正在学习Swing并创建了一个示例GUI。我正在尝试按照确切的顺序实现以下目标......

  1. 用户在一些文本字段中输入文字。
  2. 用户点击“启动”按钮。
  3. “启动”按钮被禁用。
  4. 后台线程产生并处理文本字段中的文本。
  5. 后台线程完成。
  6. “启动”按钮再次启用。
  7. 我正在尝试使用invokeandwait,如下所示,但我得到“无法从事件调度程序线程调用invokeAndWait”。我的主要方法是在同一个.class文件中,我不太确定“事件调度程序线程”到底是什么。对于这样的事情最好的方法是什么,我是否需要在我的工作线程中设置某种警报以路由回“事件调度程序线程”?

    LaunchButton代码

    private void launchButtonActionPerformed(java.awt.event.ActionEvent evt) {                                             
    
            launchButton.setEnabled(false);
    
            try {
                java.awt.EventQueue.invokeAndWait(new MyTestThread());
            } catch (Exception e) {
            }
    
            launchButton.setEnabled(true);    
    
        }   
    

    工作线程

    public class MyTestThread extends Thread {
    
        private int i = 0;
    
        public void run() {
    
            while (i < 5) {
    
                try {
                    System.out.println(i++);
                    sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
    }
    

    解决方案

    工作线程

    public class WorkerThread extends SwingWorker<Integer[], Void> {
    
        @Override
        public Integer[] doInBackground() {
    
            System.out.println("Doing in background");
    
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                    System.out.println("Doing in background" + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            return null;
        }
    
        @Override
        public void done() {
            System.out.println("Swingworker is Done");
        }
    }
    

    从我的事件调度线程(EDT)启动工作线程

        new WorkerThread().execute();
    

1 个答案:

答案 0 :(得分:1)

事件调度线程(EDT)是唯一允许访问Swing类和(几乎所有)方法的线程。 GUI的所有初始化和事件都由EDT执行。要在EDT中执行某些操作,您必须使用SwingUtilities.invokeLaterinvokeAndWait(这相当于EventQueue.invokeXXX)。这就是所有Swing程序在main中以SwingUtilities.invokeLater()开头的原因:在EDT中执行GUI初始化。

当EDT忙碌时,UI会冻结,这就是后台线程有用的原因。当你需要独立于UI(计算,I / O,传输......)进行大量工作时,你必须使用“工作线程”。

有关Swing中线程的更多信息,请参阅本教程:http://docs.oracle.com/javase/tutorial/uiswing/concurrency/

现在,你想要完成的是正确的,但你正在使用的工具不是。

您需要了解两件事:如何处理事件(如按钮按下)以及如何创建后台线程。

对于第一个,请参阅本教程: http://docs.oracle.com/javase/tutorial/uiswing/components/button.html

你只需要在按钮上添加一个ActionListener,只要按钮抛出一个事件,就会在EDT中执行监听器的actionPerformed方法。

最小例子:

JButton button = new JButton("Test button");
button.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent event)
    {
        System.out.println("The button was pressed.");
    }
}

event变量包含有用的信息,例如event.getSource()返回抛出事件的对象,在本例中为按钮。

现在,按下按钮时要执行的操作是创建工作线程。正如您在并发教程中看到的那样,使用SwingWorker类创建工作线程。在那里,您可以定义一段将在后台线程中执行的代码(在doInBackground()方法中)和一段代码,这些代码将在后台工作完成后在EDT中执行(在{ {1}}方法)。

所以你想要做这样的事情:

done()

关于此,有很多信息。阅读类的Java参考,阅读官方教程并在SO中搜索。另一个关于SwingWorkers的好教程是:http://www.javacreed.com/swing-worker-example/