在 Java (Swing) 中处理其他线程时,哪种设计模式最适合更新 GUI?
例如,想象一个对象(如自定义 JPanel)有一个 JList,并且有一个 DefaultListModel 支持它。监听 Socket 的线程可以接收数据,然后想要根据套接字传入的信息更新 JList。
我理解 SwingUtilities.invokeLater,但这看起来像是马虎的代码,因为实际上我有许多不同的函数可以调用(从非 EDT 线程)来操作不同的 GUI 组件。
我想到的想法是使用 ArrayBlockingQueue 创建某种消息传递系统。基本上,我实现了 Runnable,并在 SwingUtilities.invokeLater 方法调用中传入 this
。然后该方法被执行,但它并不真正知道要做什么,但这就是我从线程安全的 ArrayBlockingQueue 中弹出“消息”的地方。
还有比这更好的设计模式吗? 我的基本 JPanel 类
public class JPanelGUIThread extends JPanel implements Runnable
{
protected ArrayBlockingQueue<Object> guiUpdateMessages;
public JPanelGUIThread()
{
guiUpdateMessages = new ArrayBlockingQueue<Object>(10);
}
@Override
public void run()
{
while(guiUpdateMessages.size() > 0)
{
try
{
Object data = guiUpdateMessages.take();
if(data instanceof Object[])
{
handleGUIUpdateArray((Object[])data);
}
else
{
handleGUIUpdateObject(data);
}
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void handleGUIUpdateArray(Object[] objectArray)
{
}
public void handleGUIUpdateObject(Object object)
{
}
}
我的主 JPanel
public JLabel getChatLabel()
{
return chatLabel;
}
public JTextArea getChatArea()
{
return chatArea;
}
public JScrollPane getChatScrollPane()
{
return chatScrollPane;
}
public JTextField getMychat()
{
return mychat;
}
public JButton getSendButton()
{
return sendButton;
}
//This method is called from the EDT, so no need to perform adding messages
@Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == sendButton)
{
client.sendChatInformation(mychat.getText());
mychat.setText("");
}
}
public void clearOldChat()
{
Object[] data = new Object[3];
data[0] = chatArea;
data[1] = MessageType.SET;
data[2] = "";
guiUpdateMessages.add(data);
SwingUtilities.invokeLater(this);
}
@Override
public void handleGUIUpdateArray(Object[] objectArray)
{
if(objectArray[0] == chatArea)
{
if(objectArray[1] == MessageType.APPEND)
{
chatArea.append((String) objectArray[2]);
}
else if(objectArray[1] == MessageType.SET)
{
chatArea.setText((String) objectArray[2]);
}
}
}
}
最佳答案
您正在重新发明使图形用户界面正常工作的“事件队列”。已经有一个队列可以在其中添加新消息,在 java.awt.EventQueue
中实现。类。
将消息添加到事件队列的便捷方法是使用 SwingUtilities.invokeLater(Runnable)
。您传入的 Runnable 实例应包含处理事件所需的所有信息。更好的是:由于它是 Runnable,因此它可以封装处理事件所需运行的代码。
例如:以下是如何将常规“对象数组”消息封装在 Runnable 中,并将其添加到事件队列中。
public void clearOldChat() {
Object[] data = new Object[3];
data[0] = chatArea;
data[1] = MessageType.SET;
data[2] = "";
SwingUtilities.invokeLater(new GUIUpdateArrayHandler(data));
}
class GUIUpdateArrayHandler implements Runnable {
Object[] objectArray;
public GUIUpdateArray(Object[] objectArray) {
this.objectArray = objectArray;
}
public void run() {
if (objectArray[0] == chatArea) {
if (objectArray[1] == MessageType.APPEND) {
chatArea.append((String) objectArray[2]);
} else if (objectArray[1] == MessageType.SET) {
chatArea.setText((String) objectArray[2]);
}
}
}
}
就我个人而言,我会为您要发送的每种类型的消息创建单独的“Runnable”类,而不是一个通用的 GUIUpdateArrayHandler
:像AppendHandler
对于 MessageType.APPEND
, SetHandler
对于 MessageType.SET
,但如果您认为将它们放在单个处理程序中的同一位置“不那么草率”,则由您决定。
关于java - 从 Java 中的不同线程更新 GUI 的非马虎设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62927373/