如何在GUI线程之间共享信息?

时间:2012-06-06 21:41:38

标签: java multithreading swing user-interface eventqueue

我正在编写一个带有GUI(Swing)的客户端应用程序。我的两个类ClientClass和MainFrame正在运行不同的线程,但需要相互调用方法。 ClientClass在EventQueue线程(displayGUI())的应用程序生命周期中的某个时刻实例化GUI(MainFrame)。 ClientClass包含许多方法,如从客户端类线程调用的recv(),它更新MainFrame。反过来,MainFrame具有由诸如按下调用ClientClass中的方法的按钮之类的事件触发的方法。我假设EventQueue线程正在调用示例中处理按钮按下的烦人方法?

我很确定这种应用很常见,我喜欢别人的见解。我有一种感觉,我正在做的不是线程安全的,那么我该如何修复/改进这个应用程序的当前模型呢?

示例代码:

MainFrame.java:

public MainFrame(ClientClass c) {
    client = c;

    // <Misc init code here>

    btnSend = new JButton("Send");
    btnSend.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent arg0) {
            client.send("Hello!");
        }
    });
    btnSend.setBounds(171, 120, 89, 23);
    contentPane.add(btnSend);
}

public void updateElement() {
    // Update of some element here, called from ClientClass
}

ClientClass.java:

private MainFrame mainFrame;

public ClientClass() {
}

public void displayGUI() {
    final ClientClass c = this;

    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                mainFrame = new MainFrame(c);
                mainFrame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public void send(String msg) {
    // Socket send operations here
    // Currently called by the GUI's EventQueue thread?
}

public void recv() {
    // Socket recv operations here
    mainFrame.updateElement();
}

2 个答案:

答案 0 :(得分:3)

在这种特殊情况下,Xeon的回答可能对您更直接有用,但作为一般原则,您可能希望阅读Singletons

通过创建单个Singleton(在您描述的情况下通常称为Manager或某些类型),您可以拥有一个执行与您的应用程序关联的“工作”的类,并具有GUI线程( s)将任务发送给该单身人士。

答案 1 :(得分:2)

您可以使用SwingUtilities在EDT上调用代码(在UI线程上)。

在UI线程上调用鼠标单击 - 因此您应该在后台调用send(如果需要很长时间则不阻止UI)。

recv方法上,如果更改GUI状态(JLabel文本等),则应在UI线程上调用mainFrame.updateElement(); - 您可以通过以下方式执行此操作:

SwingUtilities.invokeLater(new Runnable() {... //

一般来说 - 你做的任何事情都可能影响你应该在EDT上做的GUI元素(更改文本,无效,添加组件等)。

可能阻止用户界面的所有内容都应该在后台执行 - 产生新的Thread

如果你需要阻止任何事件并等待背景 - 你可以显示模态JDialog(请记住你应该将它隐藏在finally块中 - 以防万一)

您还应该查看SwingWorker课程和tutorial