java - 从 Java 中的不同线程更新 GUI 的非马虎设计模式

标签 java multithreading user-interface edt

在 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/

相关文章:

java - Android:当我运行该应用程序时,它崩溃了

c# - 当您在 C# 任务等待程序上调用 `OnCompleted()` 时,您如何等待 OnCompleted 调用中给出的新作业?

java - 我在while循环中嵌套的if语句遇到Java问题

java - 在java字符串中存储反斜杠和正斜杠

Python线程在单个核心上执行

java - Android 应用程序一开始就崩溃

java - GUI 中的延迟初始化与急切初始化

python - 我如何在pyqt中创建一个搜索栏

java - 请求的资源不可用 Glassfish 4

Python多线程和不一致的输出