Search code examples
javaswinguser-interfacemodal-dialogjdialog

How to create a modal JDialog on top of another modal JDialog


I have a modal settings dialog which is a JDialog. In this settings window I placed some components including a button to yet another modal settings dialog which is also a JDialog. I made them JDialogs because that is the only way I know of to make a modal dialog.

The problem is this: when I create the main settings dialog I have to construct the JDialog either without a parent Frame or with a parent Frame. Since my main window is a JFrame, I can just pass that to the main settings dialog constructor. But when I want to create the second modal settings dialog which should have the main settings dialog as a parent, I can't find a way to get the (J)Frame of the JDialog. I do want to pass that main settings dialog as a parent so that the second settings dialog centers on it when it is shown. Let's assume the second settings dialog has no constructor for passing a location, just the constructors of the JDialog.

Is there a way to get the (J)Frame of a JDialog? Is there a design flaw in my setup and should I have used something else for these settings dialogs? (And if so, how should I make these alternative settings dialogs modal?)

Thank you for your help, Erik

UPDATE: Thank you all for your answers. They led me to understand that apparently it's not absolutely necessary to have an owner for a JDialog. I thought this was needed for the dialog to be able to disable the owner until the dialog is closed, but apparently the modality is independent of the owner. I also noticed that even with an owner the dialog still doesn't center on the owner, so now my code is like:

public class CustomDialog extends JDialog {
    public CustomDialog(String title) {
        setModal(true);
        setResizable(false);
        setTitle(title);

        buildGUI();
    }

    public Result showDialog(Window parent) {
        setLocationRelativeTo(parent);
        setVisible(true);
        return getResult();
    }
}

This also allows for modal dialogs in modal dialogs.

Thanks for all your help!


Solution

  • Not sure what exactly you have as a problem, but here is an example on how you can have multiple modal dialogs:

    import java.awt.BorderLayout;
    import java.awt.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    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 TestDialog {
    
        protected static void initUI() {
            JPanel pane = newPane("Label in frame");
            JFrame frame = new JFrame("Title");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(pane);
            frame.pack();
            frame.setVisible(true);
    
        }
    
        public static JPanel newPane(String labelText) {
            JPanel pane = new JPanel(new BorderLayout());
            pane.add(newLabel(labelText));
            pane.add(newButton("Open dialog"), BorderLayout.SOUTH);
            return pane;
        }
    
        private static JButton newButton(String label) {
            final JButton button = new JButton(label);
            button.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    Window parentWindow = SwingUtilities.windowForComponent(button);
                    JDialog dialog = new JDialog(parentWindow);
                    dialog.setLocationRelativeTo(button);
                    dialog.setModal(true);
                    dialog.add(newPane("Label in dialog"));
                    dialog.pack();
                    dialog.setVisible(true);
                }
            });
            return button;
        }
    
        private static JLabel newLabel(String label) {
            JLabel l = new JLabel(label);
            l.setFont(l.getFont().deriveFont(24.0f));
            return l;
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    initUI();
                }
            });
        }
    }