David Nguyen David Nguyen - 20 days ago 5
Java Question

Java,Swing - JPanel doesn't appear in JFrame as expected

I got a java class called

PleaseWait
and want to call it whenever a heavy task is in progress. When my program does a heavy task, in the first row in my
actionListener
I set a variable of this class
setVisible(true)
then set
setVisible(true)
at the end of the
actionListener
.

Somehow the
JPanel
in this class does not appear when I call it, it's just a window with title as set and white blank content. Here's my code:

public class PleaseWait extends JFrame{

public PleaseWait(){

Toolkit toolkit = Toolkit.getDefaultToolkit();

Dimension screenDimensions = toolkit.getScreenSize();
setSize(300,100); //set size based on screen size
setTitle("Please wait");
Container container = getContentPane();
setLocation(new Point(screenDimensions.width*1/4+200, screenDimensions.height*1/4+200)); //set location based on screen size

JPanel panel = new JPanel();
JLabel wait = new JLabel("Please wait");
Dimension buttonsSize = new Dimension(300,100);
panel.setPreferredSize(buttonsSize);
wait.setPreferredSize(buttonsSize);
panel.setLayout(new BorderLayout());
panel.add(wait, BorderLayout.CENTER);
container.add(panel);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false); //unresizable
}

Answer

The key is not in the code you've posted, but in this line:

and want to call it whenever a heavy task is in progress

You're running a "heavy" task, and while you're running it, Swing is not painting this GUI, because you're likely running that task on the Swing event thread, and doing so freezes the thread, and your GUI.

Solution: use a background thread such as is obtainable through a SwingWorker, to run the "heavy" task.

Other side issues:

  • This appears to be a "dependent" or "sub" window off of the main application. If so, it should not be a JFrame since an application should only have one main application window, but rather it should be a JDialog.
  • You're using setPreferredSize(...) and hard-coding your component sizes, something fraught with problems.

e.g.,

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class TestPleaseWait {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            MainPanel mainPanel = new MainPanel();
            JFrame frame = new JFrame("Application");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

class MainPanel extends JPanel {
    private static final int PREF_W = 600;
    private static final int PREF_H = 450;

    public MainPanel() {
        add(new JButton(new AbstractAction("Without Background Thread") {

            @Override
            public void actionPerformed(ActionEvent e) {
                final PleaseWait wait = new PleaseWait();
                wait.setVisible(true);
                try {
                    Thread.sleep(4000);
                } catch (InterruptedException e1) {
                }
                wait.setVisible(false);
            }
        }));
        add(new JButton(new AbstractAction("With Background Thread") {

            @Override
            public void actionPerformed(ActionEvent e) {
                final PleaseWait wait = new PleaseWait();
                wait.setVisible(true);
                new Thread(() -> {
                    try {
                        Thread.sleep(4000);
                    } catch (InterruptedException e1) {
                    }
                    SwingUtilities.invokeLater(() -> {
                        wait.setVisible(false);
                    });

                }).start();
            }
        }));
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }
}

class PleaseWait extends JFrame {

    public PleaseWait() {

        Toolkit toolkit = Toolkit.getDefaultToolkit();

        Dimension screenDimensions = toolkit.getScreenSize();
        setSize(300, 100); // set size based on screen size
        setTitle("Please wait");
        Container container = getContentPane();
        setLocation(new Point(screenDimensions.width * 1 / 4 + 200,
                screenDimensions.height * 1 / 4 + 200));

        JPanel panel = new JPanel();
        JLabel wait = new JLabel("Please wait");
        Dimension buttonsSize = new Dimension(300, 100);
        panel.setPreferredSize(buttonsSize);
        wait.setPreferredSize(buttonsSize);
        panel.setLayout(new BorderLayout());
        panel.add(wait, BorderLayout.CENTER);
        container.add(panel);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false); // unresizable
    }
}