Search code examples
javaswingjdialog

How to wait until JDialog is fully created


I need to calculate window decorations somehow. So I override JDialog's constructor. But when I call get_decoration_size() it sometimes returns wrong values. And my thought was: window creates later than get_decoration_size() executes(strange, because both in same thread and in same constructor). So I decided to sleep for a second, and it worked, and now decorations always valid.

My question is: is there a way to "join" to the creating process(wait until window is shown by setVisible(true))? If so, it must be something to replace unsafe_sleep(1000).

package swing.window;

import db.db;

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

import static swing.util.*;
import static util.util.unsafe_sleep;

public class calc_decor extends JDialog {
        {
                //some initializations
                setLayout(null);
                setResizable(false);
                JLabel label = new JLabel("Loading...");
                add(label);
                setxy(label, 3, 3);
                fit(label);
                setsize(this, label.getWidth() + 100, label.getHeight() + 100);
                window_to_center(this);

                setVisible(true);//trying to draw

                unsafe_sleep(1000);//without that it looks like get_decoratoin_size()
                                   //is called before setVisible(true)

                db.sysdecor = get_decoration_size();//trying to get decorations
                dispose();
        }

        private Dimension get_decoration_size() {
                Rectangle window = getBounds();
                Rectangle content = getContentPane().getBounds();
                int width = window.width - content.width;
                int height = window.height - content.height;
                return new Dimension(width, height);
        }
}

Solution

  • I had to assume a lot to create a runnable example.

    Here's the result of your getDecorationSize method. The line didn't print until I closed the JDialog.

    java.awt.Dimension[width=16,height=39]
    

    And here's the code I used.

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Rectangle;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BorderFactory;
    import javax.swing.JButton;
    import javax.swing.JDialog;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class JDialogTest implements Runnable {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new JDialogTest());
        }
    
        private JFrame frame;
    
        @Override
        public void run() {
            frame = new JFrame("JDialog Test");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            frame.add(createMainPanel());
    
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private JPanel createMainPanel() {
            JPanel panel = new JPanel(new BorderLayout());
            panel.setBorder(BorderFactory.createEmptyBorder(
                    150, 100, 150, 100));
            panel.setPreferredSize(new Dimension(400, 400));
    
            JButton button = new JButton("Open JDialog");
            button.addActionListener(new ButtonListener());
            panel.add(button);
    
            return panel;
        }
    
        public class ButtonListener implements ActionListener {
    
            @Override
            public void actionPerformed(ActionEvent e) {
                new CalculateDecor(frame, "Spash Screen");
            }
    
        }
    
        public class CalculateDecor extends JDialog {
    
            private static final long serialVersionUID = 1L;
    
            public CalculateDecor(JFrame frame, String title) {
                super(frame, true);
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
                setTitle(title);
    
                JPanel panel = new JPanel(new BorderLayout());
                panel.setPreferredSize(new Dimension(200, 200));
    
                JLabel label = new JLabel("Loading...");
                label.setHorizontalAlignment(JLabel.CENTER);
                panel.add(label);
    
                add(panel);
                pack();
                setLocationRelativeTo(frame);
                setVisible(true);
    
                System.out.println(getDecorationSize());
            }
    
            private Dimension getDecorationSize() {
                Rectangle window = getBounds();
                Rectangle content = getContentPane().getBounds();
                int width = window.width - content.width;
                int height = window.height - content.height;
                return new Dimension(width, height);
            }
    
        }
    
    }