java - Java swing 应用程序在线程“AWT-EventQueue-0”中抛出 NullPointerException,原因不明
问题描述
我使用 swing 包在 Java 中创建了一个控制台应用程序,但它有一个问题。首先是应用程序的工作原理:
应用程序在屏幕上打开一个 JFrame(Console 类),其中包含一个 JPanel(ConsoleScreen 类)。JPanel 只包含一个不可编辑、可滚动的 JTextArea。控制台有 3 种不同的方法可以通过编程方式调用: 1:打印(将文本打印到控制台) 2:输入(从控制台获取内联输入并返回) 3:空(清空控制台)
有关输入法的更多信息:
当调用输入法时,它使文本区域暂时可编辑,并允许用户输入内联输入。但是,它禁止它们格式化文本区域上的其余文本(通过使用 TextAreaDocumentFilter 类的实例)。在等待输入的同时,程序在主线程上反复调用 sleep(long millis) 方法,以尽可能少地浪费 CPU 时间。另外,文本区域有一个DocumentListener,一旦用户点击回车,为了移动到下一行,在主线程调用interrupt()方法,使程序停止等待输入,文本区域再次变得不可编辑。然后,返回用户给出的内联输入。
问题:
问题与输入法有关。基本上,每当我调用该方法并从控制台获取输入时,一切似乎都工作正常(正确的结果显示在控制台上并返回正确的输入)。然而,与此同时,几乎每次程序从控制台获取输入时,线程“AWT-EventQueue-0”都会抛出 NullPointerException,我不明白为什么。我尝试将程序的许多不同部分包含在 try/catch 语句中,但仍然抛出异常,就好像什么都没有改变一样。此外,我尝试在程序的几乎所有地方添加打印语句,拼命寻找错误的根源,但没有用。
你能帮我解决这个问题,或者至少告诉我为什么会这样吗?这是控制台的代码、一个测试程序和我得到的最常见的堆栈跟踪之一。尝试运行测试程序,然后自己查看错误。感谢您的关注!
控制台类:
package interpreter;
import javax.swing.JFrame;
final class Console extends JFrame{
private ConsoleScreen screen;
Console(){
setTitle("Console");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setUndecorated(false);
screen = new ConsoleScreen();
add(screen);
setVisible(true);
}
void print(String text) {
screen.print(text);
}
String input() {
return screen.input();
}
void empty() {
screen.empty();
}
}
ConsoleScreen 类:
package interpreter;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.event.DocumentListener;
import javax.swing.event.DocumentEvent;
final class ConsoleScreen extends JPanel{
Thread mainThread;
private JTextArea textArea;
private DocumentListener textAreaDocumentListener;
private TextAreaDocumentFilter textAreaDocumentFilter;
private boolean takingInput;
private int inputStartIndex = 0; /*text index after which input is taken */
ConsoleScreen(){
mainThread = Thread.currentThread();
textAreaDocumentFilter = new TextAreaDocumentFilter();
textAreaDocumentListener = new TextAreaDocumentListener();
setLayout(new GridLayout(1, 1));
fillScreen();
}
void fillScreen() {
textArea = new JTextArea("");
textArea.setBackground(Color.BLACK);
textArea.setForeground(Color.WHITE);
textArea.setCaretColor(Color.WHITE);
textArea.setFont(new Font("Consolas", Font.PLAIN, 25));
textArea.setWrapStyleWord(true);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.getDocument().addDocumentListener(textAreaDocumentListener);
((AbstractDocument)textArea.getDocument()).setDocumentFilter(textAreaDocumentFilter);
JScrollPane textAreaScroller = new JScrollPane(textArea);
textAreaScroller.setBorder(null);
add(textAreaScroller);
}
//prints text to the console
void print(String text) {
textArea.append(text);
textArea.setCaretPosition(textArea.getText().length());
inputStartIndex += text.length();
}
//takes one line of input from the console
String input() {
takingInput = true;
textArea.setEditable(true);
while(takingInput) {
try {
Thread.sleep(999999999);
}catch(InterruptedException e) {break;}
}
textArea.setEditable(false);
String inputText = textArea.getText().substring(inputStartIndex, textArea.getText().length() - 1);
inputStartIndex = textArea.getText().length();
return inputText;
}
//empties the console
void empty() {
textArea.setText("");
inputStartIndex = 0;
}
/* does not allow the user to format the text behind the inputStartIndex */
private class TextAreaDocumentFilter extends DocumentFilter {
public void insertString(final FilterBypass fb, final int offset, final String string, final AttributeSet attr)
throws BadLocationException {
if (!takingInput || offset >= inputStartIndex)
super.insertString(fb, offset, string, attr);
}
public void remove(final FilterBypass fb, final int offset, final int length) throws BadLocationException {
if (!takingInput || offset >= inputStartIndex)
super.remove(fb, offset, length);
}
public void replace(final FilterBypass fb, final int offset, final int length, final String text, final AttributeSet attrs)
throws BadLocationException {
if (!takingInput || offset >= inputStartIndex)
super.replace(fb, offset, length, text, attrs);
}
}
/* makes the program stop receiving input once the user has moved to the next line of the console */
private class TextAreaDocumentListener implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
if(takingInput) {
String text = textArea.getText();
if(text.length() > inputStartIndex && text.charAt(text.length() - 1) == '\n') {
mainThread.interrupt();
takingInput = false;
}
}
}
@Override
public void removeUpdate(DocumentEvent e) {}
@Override
public void changedUpdate(DocumentEvent e) {
insertUpdate(e);
}
};
}
测试类:
package interpreter;
class Test {
public static void main(String[] args) {
Console console = new Console();
String input = "";
do {
console.print("Enter a string: ");
input = console.input();
console.print("String entered: " + input + "\n\n");
}while(!input.equals("END"));
}
}
我得到的一个常见堆栈跟踪:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "javax.swing.text.JTextComponent.getHighlighter()" because "host" is null
at java.desktop/javax.swing.text.WrappedPlainView$WrappedLine.paint(WrappedPlainView.java:716)
at java.desktop/javax.swing.text.BoxView.paintChild(BoxView.java:162)
at java.desktop/javax.swing.text.BoxView.paint(BoxView.java:434)
at java.desktop/javax.swing.text.WrappedPlainView.paint(WrappedPlainView.java:501)
at java.desktop/javax.swing.plaf.basic.BasicTextUI$RootView.paint(BasicTextUI.java:1530)
at java.desktop/javax.swing.plaf.basic.BasicTextUI.paintSafely(BasicTextUI.java:759)
at java.desktop/javax.swing.plaf.basic.BasicTextUI.paint(BasicTextUI.java:917)
at java.desktop/javax.swing.plaf.basic.BasicTextUI.update(BasicTextUI.java:896)
at java.desktop/javax.swing.JComponent.paintComponent(JComponent.java:797)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1643)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1618)
at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
解决方案
推荐阅读
- gstreamer - GStreamer 教程 3 无法链接视频板
- python-2.7 - 如何从 .txt 文件中提取数据(时间)?
- javascript - 将鼠标悬停事件传递给下层,同时覆盖具有菜单的 div 元素保持可点击状态
- android - 不能设置外键为空,多个外键
- python-2.7 - 如何检查 Python 字典列表中是否存在键/值?
- z3 - 如何使用 c++ 在 z3 中为现有声明的函数添加新约束?
- javascript - 在不使用名称标签的情况下为不同的输入创建通用的 onChange() 函数
- android - Android中的浮动视频视图
- java - 使用插入排序对字符串开头的元音进行排序
- firebase - 使用 expo + firebase 发送推送通知