首页 > 解决方案 > 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)

标签: javamultithreadingswingnullpointerexceptionawt

解决方案


推荐阅读