JavaSwing偶尔会出现NullPointerException,但没有指出它在我的代码中发生的位置

JavaSwing偶尔会出现NullPointerException,但没有指出它在我的代码中发生的位置,java,multithreading,swing,nullpointerexception,irc,Java,Multithreading,Swing,Nullpointerexception,Irc,我正在为一项任务制作一个聊天客户端,我已经设法让一切都运行得很好。但是,我有一个错误,根本找不到原因。将消息打印到我的聊天窗口时,我会收到NullPointerException。问题是,代码仍然做它应该做的事情,而且它非常不一致。我可以打印5条消息并得到5次,或者打印20条消息却一条也得不到 到目前为止,我已经能够将错误缩小到一个函数,但无法将其缩小到函数中的一行。我收到的错误消息也没有多大帮助。我试着注释每一行代码,但仍然无法找出哪里出了问题。我甚至试着用try-and-catch来捕捉错误

我正在为一项任务制作一个聊天客户端,我已经设法让一切都运行得很好。但是,我有一个错误,根本找不到原因。将消息打印到我的聊天窗口时,我会收到NullPointerException。问题是,代码仍然做它应该做的事情,而且它非常不一致。我可以打印5条消息并得到5次,或者打印20条消息却一条也得不到

到目前为止,我已经能够将错误缩小到一个函数,但无法将其缩小到函数中的一行。我收到的错误消息也没有多大帮助。我试着注释每一行代码,但仍然无法找出哪里出了问题。我甚至试着用try-and-catch来捕捉错误,但都没有成功

以下是导致错误所需的最低代码

import java.awt.*;
import java.util.*;

// Import window library and listeners
import javax.swing.*;
import java.awt.event.*;

// Import time libraries
import java.util.Date;
import java.text.SimpleDateFormat;

public class ChatClientTest {
    // Initialize user information
    private String nickname = "testNickname";

    // Track open windows
    private ArrayList<JFrame> windows = new ArrayList<>();

    public ChatClientTest() {
        openWindow("@ChatBot");
        openWindow("@someUser");

        // Create thread to listen to server
        Thread server = new Thread(new Runnable() {
            @Override
            public void run() {
                // Run listenToServer in separate thread
                listenToServer();
            }
        });
        // Start server listening thread
        server.start();
    }

    private void listenToServer() {
        int i = 0;
        while (true) {
            for (JFrame window : windows) {
                try {
                    Thread.sleep(2000);
                    printToWindow(window.getTitle(), nickname, "Test message" + i);
                } catch (InterruptedException e) {
                    System.out.println("Interrupted");
                }
            }
            i++;
        }
    }

    // Opens a new chat window for a given channel or user
    private void openWindow(String name) {

        // Create new JFrame with a text area and scroll bar
        JFrame frame = new JFrame(name);
        JTextArea textArea = new JTextArea(20,60);
        JScrollPane scrollBar = new JScrollPane(textArea);
        JTextArea inputArea = new JTextArea("");

        // Set text area properties
        textArea.setMargin(new Insets(5,10,20,10));
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);
        textArea.setEditable(false);

        // Set scroll bar properties
        scrollBar.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);

        // Set input field properties
        inputArea.setMargin(new Insets(5,10,5,10));
        inputArea.setLineWrap(true);
        inputArea.setWrapStyleWord(true);

        // Add event listener on input area to track enter being pressed
        inputArea.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER){
                    // Stop new line
                    e.consume();

                    // Check message isn't empty
                    if (!inputArea.getText().equals("")) {
                        // Print to the window and clear the text area
                        printToWindow(nickname, name, inputArea.getText());
                        inputArea.setText("");
                    }
                }
            }
            // These are required but don't do anything
            @Override public void keyReleased(KeyEvent e) {}
            @Override public void keyTyped(KeyEvent e) {}
        });

        // put things into the frame
        frame.add(scrollBar, BorderLayout.CENTER);
        frame.add(inputArea, BorderLayout.SOUTH);
        frame.pack();

        // Set properties of the frame
        frame.setSize(400,500);
        frame.setVisible(true);

        // Print a different starting message depending on the recipient
        if (name.startsWith("#")) { // Joining a channel
            textArea.append("Welcome, " + nickname + ", to the " + name + " channel! Be nice, start chatting and get to know some people. Leave the channel to close this window.");
        } else { // Messaging a user
            textArea.append("This is the start of your messages with " + name + ". Be nice and have fun chatting.");
        }
        windows.add(frame);
    }

    // Prints messages to/from a given channel in the appropriate chat window
    private void printToWindow(String sender, String recipient, String message) {

        // Iterate through windows
        for (JFrame window : windows) {

            // Get current timestamp
            String timestamp = new SimpleDateFormat("h:mm a").format(new Date()).toLowerCase();

            // Check who the recipient/sender is so the appropriate window is chosen
            if (recipient.equals(nickname) && window.getTitle().equalsIgnoreCase(sender)) { // User is the recipient

                // Get the JFrames textArea and scrollPane
                JScrollPane scrollPane = (JScrollPane) window.getContentPane().getComponent(0);
                JTextArea textArea = (JTextArea) scrollPane.getViewport().getView();

                // Make the textArea editable
                textArea.setEditable(true);

                // Append the message to the window and scroll window down
                textArea.append("\n\n" + sender.replace("@", "") + " | " + timestamp + "\n" + message);
                textArea.validate();
                scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
                scrollPane.validate();

                // Make it non-editable again
                textArea.setEditable(false);

            } else if (window.getTitle().equalsIgnoreCase(recipient)) { // Any other recipient

                // Get the JFrames textArea and scrollPane
                JScrollPane scrollPane = (JScrollPane) window.getContentPane().getComponent(0);
                JTextArea textArea = (JTextArea) scrollPane.getViewport().getView();

                // Make the textArea editable
                textArea.setEditable(true);

                // Append the message to the window
                textArea.append("\n\n" + sender.replace("@", "") + " | " + timestamp + "\n" + message);
                textArea.validate();
                scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
                scrollPane.validate();

                // Make it non-editable again
                textArea.setEditable(false);
            }
        }
    }

    public static void main(String[] args) {
        new ChatClientTest();
    }
}
程序仍然完全按照预期运行,它只是随机地给出这个错误


有人能帮我找到NullPointerException的原因吗?让我知道,如果有任何不清楚的是如何工作的计划,并感谢您的帮助。这是我在这里的第一篇文章,所以我希望我把所有的事情都说清楚。

猜一猜——你的代码可能不符合Swing线程规则。如果没有有效的答案,我所能做的就是猜测。也许有人可以做得更好。所有Swing组件都应该在
事件调度线程(EDT)
上更新,或者您可以得到随机结果。我正在制作一个聊天客户端-所以我猜聊天客户端运行在一个单独的线程中,这可能会导致问题。要更新GUI,需要使用SwingUtilities.invokeLater(…)。有关更多信息,请阅读Swing教程中的章节。@Cocao那么?制作一个假人,它做“网络”的事情,并产生一些类似于你期望的结果——这通常被称为stubbing@Cocao您正在启动一个调用printToWindow()的线程,该线程在所有位置操作swing组件。如前所述,这是swing线程规则所禁止的。对swing组件的所有访问都必须在事件分派线程中完成。事实上,将函数实现为
private void printToWindow(..){SwingUtilites.invokeLater(()->printtowindowenedt(…);}
(其中
printtowindowenedt
包含当前
printToWindow
方法中的所有代码)应该解决这个问题。不是很干净和优雅,但至少在那之后它的行为应该是决定性的……一个猜测——您的代码可能不符合Swing线程规则。如果没有有效的答案,我所能做的就是猜测。也许有人可以做得更好。所有Swing组件都应该在
事件调度线程(EDT)
上更新,或者您可以得到随机结果。我正在制作一个聊天客户端-所以我猜聊天客户端运行在一个单独的线程中,这可能会导致问题。要更新GUI,需要使用SwingUtilities.invokeLater(…)。有关更多信息,请阅读Swing教程中的章节。@Cocao那么?制作一个假人,它做“网络”的事情,并产生一些类似于你期望的结果——这通常被称为stubbing@Cocao您正在启动一个调用printToWindow()的线程,该线程在所有位置操作swing组件。如前所述,这是swing线程规则所禁止的。对swing组件的所有访问都必须在事件分派线程中完成。事实上,将函数实现为
private void printToWindow(..){SwingUtilites.invokeLater(()->printtowindowenedt(…);}
(其中
printtowindowenedt
包含当前
printToWindow
方法中的所有代码)应该解决这个问题。不是很干净和优雅,但至少在那之后它应该表现得果断。。。
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.text.WrappedPlainView$WrappedLine.paint(WrappedPlainView.java:584)
at javax.swing.text.BoxView.paintChild(BoxView.java:161)
at javax.swing.text.BoxView.paint(BoxView.java:433)
at javax.swing.text.WrappedPlainView.paint(WrappedPlainView.java:369)
at javax.swing.plaf.basic.BasicTextUI$RootView.paint(BasicTextUI.java:1434)
at javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:737)
at javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:881)
at javax.swing.plaf.basic.BasicTextUI.update(BasicTextUI.java:860)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JViewport.paint(JViewport.java:728)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5210)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent._paintImmediately(JComponent.java:5158)
at javax.swing.JComponent.paintImmediately(JComponent.java:4969)
at javax.swing.RepaintManager$4.run(RepaintManager.java:831)
at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)