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