How do I make non-modal dialog whose setVisible blocks?

10,494

I need to make a dialog that doesn't block input to other windows, but does block the caller so that I know when the dialog has been closed.

I usually solve this not by blocking the caller, but by using a callback of some sort - a simple interface that the dialog invokes when it's done. Let's say your dialog has an "OK" and a "Cancel" button and you need to distinguish which one is pressed. Then you could do something like this:

public interface DialogCallback {
    void ok();
    void cancel();
}

public class MyModelessDialog extends JDialog {
    private final DialogCallback cbk;
    private JButton okButton, cancelButton;        

    public MyModelessDialog(DialogCallback callback) {
        cbk = callback;
        setModalityType(ModalityType.MODELESS);

        okButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onOK();
            }
        };

        cancelButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        };

        // Treat closing the dialog the same as pressing "Cancel":
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e)  {
                onCancel();
            }
        };
    }

    private void onOK() {
        cbk.ok();
    }

    private void onCancel() {
        cbk.cancel();
    }
}

Then you just pass in an instance of DialogCallback to the constructor:

MyModelessDialog dlg = new MyModelessDialog(new DialogCallback() {
    public void onOK() { 
        // react to OK
    }
    public void onCancel() { 
        // react to Cancel
    }
 });

EDIT

Is there some rationale why setVisible's behavior depends on the modality?

Well, that's just how how modal windows are supposed to work, no? A modal window should block the current workflow when displayed, and a non-modal/modeless should not. See e.g. the Wikipedia pages on modal windows or dialog boxes.

Share:
10,494
Joonas Pulakka
Author by

Joonas Pulakka

I'm the glue that holds the gears of progress together.

Updated on June 04, 2022

Comments

  • Joonas Pulakka
    Joonas Pulakka almost 2 years

    In a Swing (J)Dialog, setModal sets the modality - that is, whether the dialog should block input to other windows or not. Then, setVisible docs say for modal dialogs:

    If the dialog is not already visible, this call will not return until the dialog is hidden by calling setVisible(false) or dispose.

    Indeed, setVisible does return right away if the dialog is not modal. Sample code:

    JDialog jd = new JDialog();
    jd.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    
    /**
     * If set to false, setVisible returns right away.
     * If set to true, setVisible blocks until dialog is disposed.
     */
    jd.setModal(false);
    
    System.out.println("setting visible");
    jd.setVisible(true);
    System.out.println("set visible returned");
    

    I want to make a dialog that doesn't block input to other windows, but still does block the caller. What is a good way to do this, now that setVisible doesn't block when the dialog is not modal?

    Is there some rationale why setVisible's behavior depends on the modality?

  • Joonas Pulakka
    Joonas Pulakka over 12 years
    Thanks, callback seems to be fine solution.
  • Joonas Pulakka
    Joonas Pulakka over 12 years
    About how modal windows are supposed to work: for example java.sun.com/developer/technicalArticles/J2SE/Desktop/javase‌​6/… talks only about blocking input to some other top-level windows in the application. It says nothing about why the caller is blocked in modal, but not in modeless cases. Blocking user input to windows and blocking program calls to methods are two completely different things, IMO. There's probably some good reason why they can't be adjusted independently of each other, but I have yet to understand it.
  • perp
    perp over 12 years
    Well, AFAIK "application modal" dialogs (which is the default modality type in AWT) halt the program flow and block their caller when invoked. And that's how they should work, to my knowledge. I don't know why the Java article you linked isn't clear on that point, but the documentation for Dialog.setVisible() definitely is.
  • Joonas Pulakka
    Joonas Pulakka over 12 years
    The documentation is clear, and maybe my understanding of modality / non-modality is incorrect. But as your callback "workaround" solution shows, there are use cases where it would be useful of a dialog to block the caller without blocking the input.
  • ManInMoon
    ManInMoon over 10 years
    @perp This does not work for me. I created interface in own file. I added buttons to public MyModelessDialog(DialogCallback but I get callbacException in thread "main" java.lang.IllegalArgumentException: adding a window to a containerk) . Would you post a full example please?
  • rayryeng
    rayryeng over 9 years
    Explain why this works.... I also don't understand the need for an answer when a more verbose (and accepted) answer is already available.
  • Joonas Pulakka
    Joonas Pulakka over 9 years
    This may work, but calling setVisible() from other than the event dispatch thread is is not safe.