Swing应用程序多线程设计模式和最佳实践

时间:2014-02-19 08:46:01

标签: java multithreading swing design-patterns

我一直在阅读很多回答和问题,但我以前从未问过任何问题。

我的问题是关于Swing应用程序中的模式和最佳实践。

假设你有一个带有JLabel的GUI类的Swing应用程序和另一个类(不是前面的内部类),它扩展了Thread并执行了一些网络操作(基本上它定期从Web API获取资源以检查是否存在给定值出现)。

当第二个类获取某个值时,我需要更新firt类的JLabel。我完全知道这应该在EDT中使用invokeLater()来完成,我的问题是如何处理从后台线程到JLabel.setText()方法的访问。

据我所知,我看到了三个解决方案:

  • 在GUI类中提供一个静态getter,并在Thread类中调用它SwingUtilities.invokeLater()
  • 在GUI类中提供一个静态方法,该方法在内部调用SwingUtilities.invokeLater()并从Thread类访问该方法(比如MyGui.updateTheLabel())
  • 将JLabel的引用传递给Thread构造函数并使用该引用使用SwingUtilities.invokeLater()
  • 更新标签

哪种解决方案更好?是否有特定的设计模式可以解决这个问题。我觉得将SwingUtilities.invokeLater()放到我想要更新GUI或创建静态getter的地方是很难看的。

谢谢:)

3 个答案:

答案 0 :(得分:2)

要在后台执行任务并在Swing应用程序中更新UI元素,您可以使用SwingWorker类。

答案 1 :(得分:2)

网络线程不应该知道JLabel。它的职责是从网络加载一些数据。在屏幕上公开这些数据是另一项任务,应该使用特殊的UI类。该类应该有一些方法,如(update(byte[]),内部调用invokeLater。该UI类的一个实例应该在创建时传递给网络线程,该线程应定期调用{{1}方法。

答案 2 :(得分:0)

我通常为我将在GUI上执行的任务定义runnables,并在需要时创建它们。局外人不需要知道如何执行更新,他们只是使用GUI的公开API。

示例:

interface NetworkUpdateListener {
    void updateFetched(String newText);
}

class Gui implements NetworkUpdateListener {
    private JLabel label;
        // ...

    @Override
    public void updateFetched(String newText) {
        SwingUtilities.invokeLater(new LabelUpdater(newText));
    }

    private final class LabelUpdater implements Runnable {
        private final String text;

        LabelUpdater(String s) { text = s; }

        @Override
        public void run() { label.setText(text); }
    }
}

其他地方,来自另一个主题:

NetworkUpdateListener listener;
// ...
listener.updateFetched(text);