如何在Java中使用SwingWorker?

2022-08-31 20:26:20

与我上一个问题相关:从Java中的另一个类调用重绘?

我是Java的新手,我看过SwingWorker上的一些教程。然而,我不确定如何使用我在上一个问题中给出的示例代码来实现它。

任何人都可以解释一下如何使用SwingWorker来理解我的代码片段和/或指向我一个像样的教程吗?我看过,但我不确定我是否理解。


答案 1

通常,SwingWorker 用于在 Swing 中执行长时间运行的任务。

在事件调度线程 (EDT) 上运行长时间运行的任务可能会导致 GUI 锁定,因此完成的任务之一是使用 SwingUtilities.invokeLaterinvokeAndWait,它保持 GUI 响应,从而在运行所需任务之前优先处理其他 AWT 事件(以 a 的形式)。Runnable

但是,问题在于它不允许将数据从执行方法返回到原始方法。这就是SwingWorker旨在解决的问题。SwingUtilitiesRunnable

Java教程中有一个关于SwingWorker的部分。

下面是一个示例,其中 a 用于在单独的线程上执行耗时的任务,并在一秒钟后显示一个包含答案的消息框。SwingWorker

首先,将进行类扩展:SwingWorker

class AnswerWorker extends SwingWorker<Integer, Integer>
{
    protected Integer doInBackground() throws Exception
    {
        // Do a time-consuming task.
        Thread.sleep(1000);
        return 42;
    }

    protected void done()
    {
        try
        {
            JOptionPane.showMessageDialog(f, get());
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

和 方法的返回类型被指定为 的第一种类型,第二种类型是用于返回 和 方法的类型,本示例中未使用和。doInBackgroundgetSwingWorkerpublishprocess

然后,为了调用 ,调用该方法。在此示例中,我们将 把 a 挂接到 a 以执行 :SwingWorkerexecuteActionListenerJButtonAnswerWorker

JButton b = new JButton("Answer!");
b.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e)
    {
        new AnswerWorker().execute();
    }
});

可以将上述按钮添加到 中,然后单击以在一秒钟后获取消息框。以下内容可用于初始化 Swing 应用程序的 GUI:JFrame

private void makeGUI()
{
    final JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.getContentPane().setLayout(new FlowLayout());

    // include: "class AnswerWorker" code here.
    // include: "JButton" b code here.

    f.getContentPane().add(b);
    f.getContentPane().add(new JButton("Nothing"));
    f.pack();
    f.setVisible(true);
}

运行应用程序后,将有两个按钮。一个标有“答案!”,另一个标有“无”。当单击“回答!”按钮时,起初不会发生任何事情,但单击“无”按钮将起作用并证明GUI是响应式的。

并且,一秒钟后,结果将显示在消息框中。AnswerWorker


答案 2

同意:

在事件调度线程 (EDT) 上运行长时间运行的任务可能会导致 GUI 锁定。

不同意:

因此,其中一件事情是使用SwingUtilities.invokeLater和roctionAndWait来保持GUI的响应。

invokeLater仍然在EDT上运行代码,并且可以冻结你的UI!试试这个:

SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

至少我,一旦我点击触发上述代码执行的操作的按钮,就无法移动鼠标。我错过了什么吗?


推荐