I've been getting this error when I press on a JButton too quickly on a JFrame, so it works if there's a slight delay between compiling the program and pressing on the button. I tried to make a splash screen/loading screen to see if I give the program more time to compile if it will work without the delay, yet thus far it still crashes if pressed too quickly. I was wondering if there is a way to pre-load it such that there doesn't need to be a delay before the button is pressed and so that the error won't exist, thanks!
(relevant pieces of code are listed, but since the entire package has a few thousand lines I'm not going to put all of it here)
This is ran in the main method.
Panels panel = new Panels();
panel.getWindow();
This is in a separate "Window" class
public Window(JPanel panel)
{
super("Knight Quest");
//loading screen
JWindow window = new JWindow();
window.getContentPane().add(new JLabel("Loading..."));
window.getContentPane().add(
new JLabel("", new ImageIcon(getClass().getResource("loading.gif")), SwingConstants.CENTER));
window.setBounds(600, 300, 400, 300);
window.setVisible(true);
try
{
Thread.sleep(2500);
} catch (InterruptedException e)
{
e.printStackTrace();
}
window.setVisible(false);
//end of loading screen
setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,550);
setLocation(525, 225);
setVisible(true);;
}
This is at the top of the Panel class
private Window window = new Window(main());
This is the main() JPanel that starts off the program (just adds stuff to a JPanel)
public JPanel main()
{
JPanel main = new JPanel();
check = "main";
main.setBackground(lightGrey);
Handler handles = new Handler();
one = new JButton("Start ");
two = new JButton("Patch Notes");
three = new JButton("Exit ");
one.addActionListener(handles);
two.addActionListener(handles);
three.addActionListener(handles);
image = new ImageIcon(getClass().getResource("templar.jpg"));
JLabel title = new JLabel("Knight Quest");
title.setFont(new Font("Serif", Font.PLAIN, 45));
JLabel mainPic = new JLabel(image);
JLabel versionNum = new JLabel("v1.1.0");
JLabel credit = new JLabel("Created and developed by Joseph Torres");
Box panel = Box.createVerticalBox();
panel.add(title);
panel.add(Box.createRigidArea(new Dimension(50, 50)));
panel.add(one);
panel.add(Box.createRigidArea(new Dimension(50,50)));
panel.add(two);
panel.add(Box.createRigidArea(new Dimension(50,50)));
panel.add(three);
panel.add(Box.createRigidArea(new Dimension(50,150)));
panel.add(versionNum);
panel.add(credit);
main.add(panel);
main.add(mainPic);
return main;
}
And the nullpointerexception is generated at
private class Handler implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent event)
{
//First Button
if(event.getSource() == one)
{
if(check.equals("main"))
{
window.setPanel(prologue());
}
}
}
}
and lastly setPanel is a a method made in the windows class that is
public void setPanel(final JPanel panel) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getContentPane().removeAll();
add(panel, BorderLayout.CENTER);
if(Panels.sizeCheck != 1)
{
setSize(600, 550);
setLocation(525, 225);
}
else
{
setSize(1000, 600);
setLocation(300, 100);
}
revalidate();
repaint();
}
});
}
This is already a huge wall of text, but those are all of the important pieces that I felt were relevant. The code itself works, its just the one issue of it loading too fast or something that I may have overlooked. Let me know if you need any more pieces of code or the full program and I'll be willing to post it. Thanks!
Edit: Stack trace
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Panels$Handler.actionPerformed(Panels.java:1228)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
You should not be using Thread.sleep()
to delay the loading of your panel. This blocks the UI thread and doesn't do what you want. Instead, use a Swing Timer
:
public Window(final JPanel panel)
{
super("Knight Quest");
//loading screen
final JWindow window = new JWindow();
window.getContentPane().add(new JLabel("Loading..."));
window.getContentPane().add(
new JLabel("", new ImageIcon(getClass().getResource("loading.gif")), SwingConstants.CENTER));
window.setBounds(600, 300, 400, 300);
window.setVisible(true);
javax.swing.Timer timer = new javax.swing.Timer(2500,
new ActionListener() {
public void actionPerformed(ActionEvent e) {
window.setVisible(false);
setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,550);
setLocation(525, 225);
setVisible(true);
}
}
);
timer.setRepeats(false);
timer.start();
}
EDIT: If the only reason for your splash screen is to give the assignment to window
a chance to complete, then there's an easy way to eliminate that: separate construction of the Window
object from the display of the panel. You could do something like this:
public Window() {
super("Knight Quest");
}
public void display(JPanel panel) {
setLayout(new BorderLayout());
add(panel, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(600,550);
setLocation(525, 225);
setVisible(true);
}
Then at the top of the Panels
class, replace this line:
private Window window = new Window(main());
with a simple declaration:
private Window window;
and move the assignment into the constructor for Panels
:
public Panels() {
// . . . other constructor stuff (if any)
window = new Window();
window.display(main());
}