1

我正在编写一个带有 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
}

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

2 回答 2

3

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

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

于 2012-06-06T22:54:47.557 回答
2

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

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

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

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

一般而言 - 您所做的任何可能影响您应该在 EDT 上执行的 GUI 元素(更改文本、无效化、添加组件等)。

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

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

您还应该查看SwingWorker类和教程

于 2012-06-06T21:52:56.920 回答