如何制作 setVisible 阻塞的非模态对话框?
Posted
技术标签:
【中文标题】如何制作 setVisible 阻塞的非模态对话框?【英文标题】:How do I make non-modal dialog whose setVisible blocks? 【发布时间】:2011-10-17 05:44:19 【问题描述】:在 Swing (J)Dialog 中,setModal 设置模态 - 即对话框是否应阻止输入到其他窗口。然后,setVisible docs 说 对于模态对话框:
如果对话框尚不可见,则此调用将不会返回,直到通过调用 setVisible(false) 或 dispose 隐藏对话框。
确实,如果对话框不是模态的,setVisible
确实会立即返回。示例代码:
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");
我想制作一个不阻止输入到其他窗口,但仍然确实阻止调用者的对话框。既然setVisible
在对话框非模态时不会阻塞,那么有什么好的方法可以做到这一点?
有什么理由为什么setVisible
的行为取决于模态吗?
【问题讨论】:
阅读文档中的上面一行:它很清楚地写着“模式对话框的注释”。 @perp:糟糕,我的错。正在编辑... 【参考方案1】:我需要创建一个不会阻止输入到其他窗口的对话框,但会阻止调用者,以便我知道对话框何时关闭。
我通常不是通过阻止调用者来解决这个问题,而是通过使用某种回调来解决这个问题 - 对话框在完成时调用的简单接口。假设您的对话框有一个“确定”和一个“取消”按钮,您需要区分按下的是哪个按钮。然后你可以这样做:
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();
然后你只需将 DialogCallback 的实例传递给构造函数:
MyModelessDialog dlg = new MyModelessDialog(new DialogCallback()
public void onOK()
// react to OK
public void onCancel()
// react to Cancel
);
编辑
setVisible 的行为取决于模态有什么理由吗?
嗯,这就是 modal 窗口应该如何工作的方式,不是吗?模态窗口应该在显示时阻止当前工作流,而非模态/非模态窗口不应该。参见例如modal windows 或 dialog boxes 上的***页面。
【讨论】:
谢谢,回调似乎是很好的解决方案。 关于模态窗口应该如何工作:例如java.sun.com/developer/technicalArticles/J2SE/Desktop/javase6/… 只讨论阻止对应用程序中其他一些***窗口的输入。它没有说明为什么 caller 在模态中被阻塞,但在非模态情况下却没有。阻止用户对窗口的输入和阻止程序调用方法是两个完全不同的事情,IMO。可能有一些很好的理由说明它们不能相互独立地调整,但我还没有理解。 好吧,AFAIK“应用程序模式”对话框(这是 AWT 中的默认模式类型)在调用时停止程序流程并阻止其调用者。据我所知,这就是他们应该如何工作的。我不知道为什么您链接的 Java 文章在这一点上不清楚,但 Dialog.setVisible() 的文档肯定是。 文档很清楚,可能我对模态/非模态的理解不正确。但正如您的回调“解决方法”解决方案所示,在某些用例中,使用对话框来阻止 caller 而不会阻止 input. @perp 这对我不起作用。我在自己的文件中创建了界面。我在 public MyModelessDialog(DialogCallback but I get callbacException in thread "main" java.lang.IllegalArgumentException: added a window to a containerk) 中添加了按钮。你能发布一个完整的例子吗?【参考方案2】:只放this.setModal(true)
,但没有在构造函数上设置父对话框:
MyDialog dlg = new JDialog();
this.setModal(true);
当你拨打setVisible(true)
时,它不会停止
【讨论】:
【参考方案3】:直接的方法是:
JDialog dialog = new JDialog(owner, ModalityType.DOCUMENT_MODAL);
【讨论】:
解释为什么会这样......我也不明白当一个更详细(和接受)的答案已经可用时需要一个答案。【参考方案4】:我找到了另一种方法来做到这一点。在扩展 javax.swing.JDialog 的进度条的构造函数中,我添加了:
setModalityType(ModalityType.APPLICATION_MODAL);
然后我覆盖了 setVisible 方法:
@Override
public void setVisible(boolean b)
if (b)
new Thread(new Runnable()
@Override
public void run()
showProgress();
).start();
else
super.setVisible(false);
在 run() 中,您可以看到对 showProgress() 的调用。这简直就是:
public void showProgress()
super.setVisible(true);
这里发生的是 JDialog 块的 setVisible() 方法。所以我覆盖了它,并在一个线程中调用了 JDialog 的 setVisible()。导致它没有阻塞。
【讨论】:
这可能有效,但从事件调度线程之外调用setVisible()
是is not safe。以上是关于如何制作 setVisible 阻塞的非模态对话框?的主要内容,如果未能解决你的问题,请参考以下文章