如果事件调度线程没有暂停,模态对话框如何等待?

时间:2014-04-13 19:15:55

标签: java multithreading swing modal-dialog

在下面的示例中,模式对话框在事件调度线程中打开。由于对话框是模态的,因此方法setVisible()在关闭之前不会返回。

有人可能会怀疑这会导致事件调度线程暂停,但这是错误的,因为按钮正在运行。

因此,setVisible()方法不会阻塞该线程。

问题是:是否可以在不阻止程序的情况下显示模态对话框?

package tests.javax.swing;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Try_JDialog_Modality2 {

    private static final Logger log = LoggerFactory.getLogger(Try_JDialog_Modality2.class);

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                AbstractAction popupAction = new AbstractAction("popup") {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JOptionPane.showMessageDialog(null, "popup");
                    }

                };

                JDialog dialog = new JDialog((JFrame)null, true);
                dialog.setLayout(new FlowLayout());
                dialog.add(new JButton(popupAction));

                dialog.pack();
                dialog.setLocationRelativeTo(null);

                dialog.setVisible(true);

                log.debug("After set visible");



            }
        });


    }

}

更新

我可以使用以下代码段执行相同操作:

//dialog.setVisible(true);
            new Thread(new Runnable() {

                @Override
                public void run() {
                    dialog.setVisible(true);
                }
            }).start();

            log.debug("After set visible");

有更短的路吗?

2 个答案:

答案 0 :(得分:3)

你的问题:

  

问题是:是否可以在不阻止程序的情况下显示模态对话框?

是的,在显示模态对话框之前调用方法。对于某些事情,最好使用回调类型的设置来完成,例如使用PropertyChangeListener或其他类型的侦听器。如果在可视化模态对话框之前设置并调用它,它应该可以工作。

至于问题的如何部分,我相信它会阻止对其他窗口的输入,但不会停止Swing事件线程。它确实可以通过调用SwingUtilities.invokeAndWait(...)来停止来自调用代码的程序流。最好查看Swing源代码以获取详细信息。


修改 关于您的更新,从不执行此操作:

new Thread(new Runnable() {

    @Override
    public void run() {
        dialog.setVisible(true);
    }
}).start();

因为您现在保证启动Swing事件线程的关闭对话框。

答案 1 :(得分:0)

dialog.setVisible(true);应在AWT Dispatcher线程上运行。所以你应该以其他方式做到。

public buttonPressed_OpenDialog_and_doTask(){
    new Thread(new Runnable() {
        @Override
        public void run() {
            /* my worker background task */
            dialog.dispose(); // at the end of task call this
        }
        }).start();
    dialog.setVisible(true);
    // we will continue when worker thread finishes
}

请注意,即使您阻止AWT事件调度程序线程(通过方法setVisible())。 AWT事件调度程序线程仍然以某种方式运行 - 因此所有AWT通知都像往常一样工作。见doc dialog.setVisible()

请注意,即使后台任务要快,并且在前一个线程中调用dialog.dispose()之前调用dialog.setVisible(true),一切都可以。幸运的是dialog.dispose()礼貌地等待直到对话变得可见。