java - NullPointerException al intentar usar el método de JPanel personalizado
swing (2)
Intento hacer una GUI para mi juego que creé hace un tiempo, y me encuentro con un pequeño problema mientras lo ejecuto.
Quiero que la salida se imprima en un JTextField en un JPanel extendido. Sin embargo, cuando lo ejecuto, aparece este error:
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.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$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.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)
Aquí está el código aplicable:
(Voy a omitir Karma.java:134 ya que este es solo el botón de reproducción).
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 (La clase utilizada para el panel de contenido) [EDITAR: Este es el contenido de la clase completa para el contexto.]
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");
}
}
Curiosamente, la GUI aparece y permanece activa después de que se produce la excepción. Simplemente no imprime la salida a JTextArea y se atasca.
Si necesita más código para el contexto, hágamelo saber por favor y lo agregaré.
EDITAR: Algunos han señalado que ciertos campos pueden no ser inicializados. Me dirigí a ellos en consecuencia. Traté de averiguar exactamente qué causaba la excepción, pero fallé. No debe ser ''newContentPane'' o ''output'' porque ambos aparecen en la pantalla cuando se inicia el programa.
Está llamando a imprimir antes de que se haya creado su JTextArea. invokeLater se está ejecutando antes de la llamada de impresión. La mejor manera de corregir (IMO) sería imprimir su declaración de salida al final de un método Runnable.run que llama a Classic.startGUI primero, iniciado a través de invokeLater, en lugar del constructor Classic :: startGUI por sí mismo
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");
Mira esto, aquí está tu error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at Classic.print(Classic.java:509)
Aquí está su Classic#print
private static void print(String text) {
newContentPane.appendOutput(text);
}
Aquí, el único escenario que arrojaría una
NullPointerException
es cuandonewContentPane
esnull
.
Sí, es posible que tenga algún código que inicialice newContentPane
, pero no está sucediendo a tiempo antes de su llamada a Classic#print
.
Entonces, ¿por qué no está sucediendo a tiempo? Al igual que lo que todos han intentado decirte, tiene que ver con el uso de invokeLater
.