如何制作 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 阻塞的非模态对话框?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WPF 中制作模态对话框?

Qt的模态对话框和非模态对话框 经常使用setAttribute (Qt::WA_DeleteOnClose)

如何制作非阻塞的javascript代码?

如何制作非阻塞的javascript代码?

模态窗口和控件显示前后

JAVA Swing中如何实现一个非阻塞的对话框。