【问题标题】:Running code in AWT Thread在 AWT 线程中运行代码
【发布时间】:2015-01-25 01:04:20
【问题描述】:

我有一个 JTextPane 用于放置聊天应用程序的聊天历史记录。目前它的内容有两个来源:

  1. 客户端线程监听服务器消息。
  2. GUI:添加到消息中的 JField 和按钮(暂时的,因为所有内容都来自服务器)

这是两种方法使用的代码:

private void appendText(String text, AttributeSet attr) {
        try {
            int len = history.getDocument().getLength();
            history.getDocument().insertString(len, text + "\n", attr);
                    // Convert the new end location
            // to view co-ordinates
            Rectangle r = history.modelToView(len);

            // Finally, scroll so that the new text is visible
            if (r != null) {
                scrollRectToVisible(r);
            }
        } catch (BadLocationException e) {
            System.out.println("Failed to append text: " + e);
        }
    }

调试我注意到代码在两种情况下都会执行,但只有在通过 GUI 在 AWT 线程中运行时才会真正显示在组件中。

因此,除非其他人有更好的想法,否则我有以下选择:

  1. 以某种方式在 AWT 上运行客户端线程。
  2. 以某种方式在 AWT 上运行 append 方法。
  3. 请使用你们中的一个人的聪明答案。

有什么想法/建议吗?

【问题讨论】:

    标签: java multithreading awt jtextpane


    【解决方案1】:

    试试这个:

    private void appendText(String text, AttributeSet attr) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                // your method code here
            }
        });
    }
    

    看起来您正在尝试在 AWT 线程之外更新 swing 组件,因为您是直接从客户端线程调用 appendText。你不能那样做。现在,如果您使用 EventQueue.invokeLater,它将确保更新摆动组件的代码在 AWT 线程中执行,无论您从哪个线程调用该方法。

    【讨论】:

    • 这是我在发布之前测试过的,但没有奏效。在方法和客户端线程中尝试了这个,结果相同。
    • 这是正确答案,我的问题与此无关。最后,这确实解决了问题背后的问题。
    【解决方案2】:

    我认为您应该创建一个类来保存有关消息的信息(如消息文本、发送者、接收者、时间戳)。像这样:

    public class ChatHistoryElement {
        private String text;
        private Date moment;
        private User sender;
        private User receiver;
        public volatile volatile AbstractList<ChatHistoryElement> chatHistory = null;
    
        public String getMessage() {
            return text;
        }
    
        public Date getMoment() {
            return moment;
        }
    
        public User getSender() {
            return sender;
        }
    
        public User getReceiver() {
            return receiver;
        }
    
        public ChatHistoryElement(String text, Date moment, User sender, User receiver) {
            this.text = text;
            this.moment = moment;
            this.sender = sender;
            this.receiver = receiver;
            if (chatHistory == null) {
                chatHistory = new ArrayList<ChatHistoryElement>();
            }
            chatHistory.add(this);
        }
    }
    

    通过使您的历史记录不稳定,您将始终能够使用ChatHistoryElement.chatHistory 访问它。

    【讨论】:

    • 不确定这与问题有什么关系。存储此列表超出了将其显示在 TextPane 上的目的。
    • 您也可以将 TextPane 定义为 volatile。问题是可以从任何线程访问 volatile 成员。我喜欢将 UI 的东西保留在 UI Thread 中,因此我相信只分享重要的东西会更好,并且 UI Thread 应该根据列表定期刷新 TextPane。所以,实际上,我相信这与这个问题有很大关系。
    猜你喜欢
    • 2022-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2012-10-02
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多