How do I make non-modal dialog whose setVisible blocks?
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.
Joonas Pulakka
I'm the glue that holds the gears of progress together.
Updated on June 04, 2022Comments
-
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 over 12 yearsThanks, callback seems to be fine solution.
-
Joonas Pulakka over 12 yearsAbout how modal windows are supposed to work: for example java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/… 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 over 12 yearsWell, 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 over 12 yearsThe 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 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 over 9 yearsExplain 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 over 9 yearsThis may work, but calling
setVisible()
from other than the event dispatch thread is is not safe.