尝试使用自定义 JPanel 中的方法时出现 NullPointerException
NullPointerException when trying to use method from custom JPanel
我正在尝试为我不久前创建的游戏制作 GUI,但我 运行在 运行 制作它时遇到了一个小问题。
我想将输出打印到扩展 JPanel 中的 JTextField。但是,当我 运行 它时,它出现了这个错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Classic.print(Classic.java:509)
at Classic.play(Classic.java:43)
at Karma.actionPerformed(Karma.java:134)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6525)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6290)
at java.awt.Container.processEvent(Container.java:2234)
at java.awt.Component.dispatchEventImpl(Component.java:4881)
at java.awt.Container.dispatchEventImpl(Container.java:2292)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
at java.awt.Container.dispatchEventImpl(Container.java:2278)
at java.awt.Window.dispatchEventImpl(Window.java:2750)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue.run(EventQueue.java:731)
at java.awt.EventQueue.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
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)
这里是适用的代码:
(我将跳过 Karma.java:134,因为这只是播放按钮。)
Classic.java
import static javax.swing.SwingUtilities.invokeLater; //This is to show where invokeLater comes from
...
public class Classic extends Game {
private static JFrame gui;
private static GUIClassic newContentPane;
...
public void play() {
invokeLater(Classic::startGUI);
//The next line is "Classic.java:43
//length, difficulty, and log are all strings that were initialized when the game was instantiated
print("Selected Options:\nLength: " + length + "\nDifficulty: " + difficulty + "\nOutput Log? " + log + "\n");
...
}
private static void startGUI() {
gui = new JFrame("Karma :: Classic Mode");
gui.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
newContentPane = new GUIClassic();
newContentPane.setOpaque(true);
gui.setContentPane(newContentPane);
gui.pack();
gui.setVisible(true);
}
private static void print(String text) {
newContentPane.appendOutput(text);
}
GUIClassic.java(用于内容面板的 class)
[编辑:这是上下文的完整 class 内容。]
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GUIClassic extends JPanel implements ActionListener {
private JTextArea output;
private JTextField input;
private boolean inputReady;
private String inputText;
public GUIClassic() {
super();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
output = new JTextArea(15, 15);
output.setEditable(false);
JScrollPane outputScroll = new JScrollPane(output);
input = new JTextField("",40);
add(outputScroll);
add(Box.createRigidArea(new Dimension(0,5)));
add(input);
}
public void actionPerformed(ActionEvent e) {
inputText = input.getText();
inputReady = true;
input.setText("");
}
public boolean isInputReady() {
return inputReady;
}
public String getInput() {
if (!isInputReady())
return null;
inputReady = false;
return inputText;
}
public void appendOutput(String addition) {
output.append(addition + "\n");
}
}
有意思的是,GUI在异常发生后确实会弹出并一直存在。它只是不将输出打印到 JTextArea 并卡住。
如果您需要更多上下文代码,请告诉我,我会添加它。
编辑:有些人指出某些字段可能未初始化。我相应地解决了这些问题。我试图找出导致异常的确切原因,但失败了。它不应该是 'newContentPane' 或 'output',因为它们都会在程序启动时出现在屏幕上。
您在创建 JTextArea 之前调用了 print。 invokeLater 在 print 调用之前 运行。修复 (IMO) 的最佳方法是在 Runnable.run 方法末尾打印输出语句,该方法首先调用 Classic.startGUI,通过 invokeLater 启动,而不是 Classic::startGUI 构造函数本身
invokeLater(Classic::startGUI);
//The next line is "Classic.java:43
//length, difficulty, and log are all strings that were initialized when the game was instantiated
print("Selected Options:\nLength: " + length + "\nDifficulty: " + difficulty + "\nOutput Log? " + log + "\n");
检查一下,这是你的错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at Classic.print(Classic.java:509)
这是你的 Classic#print
private static void print(String text) {
newContentPane.appendOutput(text);
}
Here, the only scenario that would throw a
NullPointerException
is when newContentPane
equalsnull
.
是的,您可能有一些初始化 newContentPane
的代码,但它没有在您调用 Classic#print
之前及时发生。
那么,为什么没有及时发生呢?就像每个人一直试图告诉你的那样,它与 invokeLater
.
的使用有关
我正在尝试为我不久前创建的游戏制作 GUI,但我 运行在 运行 制作它时遇到了一个小问题。
我想将输出打印到扩展 JPanel 中的 JTextField。但是,当我 运行 它时,它出现了这个错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Classic.print(Classic.java:509)
at Classic.play(Classic.java:43)
at Karma.actionPerformed(Karma.java:134)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2346)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6525)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6290)
at java.awt.Container.processEvent(Container.java:2234)
at java.awt.Component.dispatchEventImpl(Component.java:4881)
at java.awt.Container.dispatchEventImpl(Container.java:2292)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4898)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4533)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4462)
at java.awt.Container.dispatchEventImpl(Container.java:2278)
at java.awt.Window.dispatchEventImpl(Window.java:2750)
at java.awt.Component.dispatchEvent(Component.java:4703)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access0(EventQueue.java:97)
at java.awt.EventQueue.run(EventQueue.java:709)
at java.awt.EventQueue.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue.run(EventQueue.java:731)
at java.awt.EventQueue.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
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)
这里是适用的代码:
(我将跳过 Karma.java:134,因为这只是播放按钮。)
Classic.java
import static javax.swing.SwingUtilities.invokeLater; //This is to show where invokeLater comes from
...
public class Classic extends Game {
private static JFrame gui;
private static GUIClassic newContentPane;
...
public void play() {
invokeLater(Classic::startGUI);
//The next line is "Classic.java:43
//length, difficulty, and log are all strings that were initialized when the game was instantiated
print("Selected Options:\nLength: " + length + "\nDifficulty: " + difficulty + "\nOutput Log? " + log + "\n");
...
}
private static void startGUI() {
gui = new JFrame("Karma :: Classic Mode");
gui.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
newContentPane = new GUIClassic();
newContentPane.setOpaque(true);
gui.setContentPane(newContentPane);
gui.pack();
gui.setVisible(true);
}
private static void print(String text) {
newContentPane.appendOutput(text);
}
GUIClassic.java(用于内容面板的 class) [编辑:这是上下文的完整 class 内容。]
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GUIClassic extends JPanel implements ActionListener {
private JTextArea output;
private JTextField input;
private boolean inputReady;
private String inputText;
public GUIClassic() {
super();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
output = new JTextArea(15, 15);
output.setEditable(false);
JScrollPane outputScroll = new JScrollPane(output);
input = new JTextField("",40);
add(outputScroll);
add(Box.createRigidArea(new Dimension(0,5)));
add(input);
}
public void actionPerformed(ActionEvent e) {
inputText = input.getText();
inputReady = true;
input.setText("");
}
public boolean isInputReady() {
return inputReady;
}
public String getInput() {
if (!isInputReady())
return null;
inputReady = false;
return inputText;
}
public void appendOutput(String addition) {
output.append(addition + "\n");
}
}
有意思的是,GUI在异常发生后确实会弹出并一直存在。它只是不将输出打印到 JTextArea 并卡住。
如果您需要更多上下文代码,请告诉我,我会添加它。
编辑:有些人指出某些字段可能未初始化。我相应地解决了这些问题。我试图找出导致异常的确切原因,但失败了。它不应该是 'newContentPane' 或 'output',因为它们都会在程序启动时出现在屏幕上。
您在创建 JTextArea 之前调用了 print。 invokeLater 在 print 调用之前 运行。修复 (IMO) 的最佳方法是在 Runnable.run 方法末尾打印输出语句,该方法首先调用 Classic.startGUI,通过 invokeLater 启动,而不是 Classic::startGUI 构造函数本身
invokeLater(Classic::startGUI);
//The next line is "Classic.java:43
//length, difficulty, and log are all strings that were initialized when the game was instantiated
print("Selected Options:\nLength: " + length + "\nDifficulty: " + difficulty + "\nOutput Log? " + log + "\n");
检查一下,这是你的错误:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at Classic.print(Classic.java:509)
这是你的 Classic#print
private static void print(String text) {
newContentPane.appendOutput(text);
}
Here, the only scenario that would throw a
NullPointerException
is whennewContentPane
equalsnull
.
是的,您可能有一些初始化 newContentPane
的代码,但它没有在您调用 Classic#print
之前及时发生。
那么,为什么没有及时发生呢?就像每个人一直试图告诉你的那样,它与 invokeLater
.