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



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

的?

我很确定这种应用程序非常普遍,我喜欢其他人的洞察力。我有一种感觉,我正在做的事情不是线程安全的,那么我该如何修复/改进此应用程序的当前模型?

示例代码:

大型机.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
}

客户端类.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();
}

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

通过创建单个单例(在您描述的情况下通常称为管理器或类似名称),您可以拥有一个执行与应用程序关联的"工作"的类,并让 GUI 线程将任务发送到该单例。

您可以使用

SwingUtilities在 EDT(在 UI 线程上)上调用代码。

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

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

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

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

以及所有可能阻止用户界面的事情,您应该在后台执行 - 生成新Thread .

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

您还应该查看 SwingWorker 类和教程。

最新更新