我正在编写一个带有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();
}
答案 0 :(得分:3)
通过创建单个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。