How do I make non-modal dialog whose setVisible blocks?
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 d开发者_如何学JAVAepends on the modality?
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.
Just put this.setModal(true)
but not set the parent dialog on the constructor:
MyDialog dlg = new JDialog();
this.setModal(true);
When you call setVisible(true)
, it wont stop
The direct approach is by:
JDialog dialog = new JDialog(owner, ModalityType.DOCUMENT_MODAL);
I have found another way to do this. In the constructor of my progress bar, which extends javax.swing.JDialog, I added:
setModalityType(ModalityType.APPLICATION_MODAL);
I then overrode the setVisible method:
@Override
public void setVisible(boolean b) {
if (b) {
new Thread(new Runnable() {
@Override
public void run() {
showProgress();
}
}).start();
} else {
super.setVisible(false);
}
}
In the run(), you can see a call to showProgress(). This simply is:
public void showProgress() {
super.setVisible(true);
}
What happens here, is the setVisible() method of JDialog blocks. So I overrode it, and called setVisible() of the JDialog, in a thread. Resulting in it not blocking.
精彩评论