2

What is the correct way of disposing a frame which is created inside a Runnable object?

The code below returns a null pointer exception when the endDialog is called before the LoadingRunnable has completed its constructor. How can the endDialog be executed after the constructor has finished?

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LoadingRunnable implements Runnable
{
    private JFrame jFrame;

    @Override
    public void run()
    {
        jFrame = new JFrame("Window");
        JPanel jPanel = new JPanel();
        JLabel label = new JLabel("Loading...");
        jPanel.add(label);
        jFrame.setContentPane(jPanel);
        jFrame.pack();
        jFrame.setVisible(true);
    }

    public void endDialog()
    {
        jFrame.setVisible(false);
        jFrame.dispose();
    }

    public static void main(String args[])
    {
        LoadingRunnable l = new LoadingRunnable();
        SwingUtilities.invokeLater(l);
        //work done here
        l.endDialog();
    }
};
dendini
  • 3,842
  • 9
  • 37
  • 74

2 Answers2

2

You have a concurrency problem here because SwingUtilities.invokeLater() schedules your runnable class execution in the Event Dispatch Thread asynchronously while your main thread's flow still running, causing a NPE.

The correct way to dispose a frame is through events, just as Swing is designed to be used. For instance by clicking the "X" (close) button or by dispatching a WindowEvent:

frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));

You may want to take a look to this question too: Optional way to close a dialog window

In addition

If you just want to show something during your application start up, then you can use SplashScreen API instead of JFrame. See How to Create a Splash Screen for further details.

enter image description here

Based on your previous question and this new one, I'd suggest you read the whole Concurrency in Swing tutorial to understand about common concurrency problems in Swing and how to deal with them.

Community
  • 1
  • 1
dic19
  • 17,821
  • 6
  • 40
  • 69
  • It's exactly there the problem, I want the "loading..." frame to show in the EDT and the main thread to communicate to the frame when to hide. Is there some example? – dendini Jul 17 '14 at 13:57
0

Ok found how:

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Loading
{

    private JFrame jFrame;

    public void startDialog()
    {
        jFrame = new JFrame("Window");
        JPanel jPanel = new JPanel();
        JLabel label = new JLabel("Loading...");
        jPanel.add(label);
        jFrame.setContentPane(jPanel);
        jFrame.pack();
        jFrame.setVisible(true);
    }

    public void endDialog()
    {
        jFrame.setVisible(false);
        jFrame.dispose();
    }

    public static void main(String args[])
    {
        final Loading l = new Loading();
        for (int i = 0; i < 200; i++)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    l.startDialog();
                }
            });
            SwingUtilities.invokeLater(new Runnable()
            {
                public void run()
                {
                    l.endDialog();
                }
            });
        }
    }
};
dendini
  • 3,842
  • 9
  • 37
  • 74
  • 1
    What's with the loop? Maybe you should look into a [Swing Timer](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) – Paul Samsotha Jul 17 '14 at 14:27
  • Ah ok no, the loop is just to show that endDialog() is never called before startDialog() thus returning a null pointer as in previous version. – dendini Jul 17 '14 at 14:33