Modal JDialog没有阻塞执行

时间:2014-06-03 10:58:53

标签: java swing modal-dialog jdialog

有没有办法在Swing中使用一个禁止任何gui活动的对话框,但同时又不会停止在设置为可见的线程上执行?

5 个答案:

答案 0 :(得分:6)

是的,可以做到。

dlg.setModal(false);

dlg.setModalityType(Dialog.ModalityType.MODELESS);

其中dlg是JDialog的实例。

答案 1 :(得分:1)

JDialog IS的基本思想是阻止底层线程,直到用户对它做出反应。如果您需要在不应该​​中断的UI线程上运行某些东西,请考虑使用额外的工作线程。这样,UI将被JDialog阻止,但底层进程不会被激活。

答案 2 :(得分:1)

从技术上讲,没有。就像MadProgrammer在评论中写道的那样,你永远不会期望在EDT之外访问任何Swing组件,包括JDialogs,因此你在问题中暗示的情况永远不会发生(除了EDT以外,任何线程都不能设置对话框可见)。

但是,你可以让它看起来像它。这就是SwingUtilities.invokeLater(Runnable)对于doc)的原因。

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BlockingDialogDemo extends JFrame {

    private Timer timer;
    private JDialog blocker;

    public BlockingDialogDemo() {
        setTitle("Blocking Dialog");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 200);
        setLocationRelativeTo(null);

        blocker = new JDialog(this, true);
        blocker.setLayout(new FlowLayout());
        blocker.setUndecorated(true);
        blocker.getRootPane().setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.black));
        blocker.add(new JLabel("I'm blocking EDT!"));    
        JProgressBar progress = new JProgressBar();
        progress.setIndeterminate(true);
        blocker.add(progress);
        blocker.pack();

        timer = new Timer(3000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                doSomeWork();
            }
        });
        timer.setRepeats(false);
        timer.start();
    }

    private void doSomeWork() {
        // this executes on-EDT
        Runnable runnable = new Runnable() {

            public void run() {
                // this executes off-EDT - never ever access Swing components here
                showBlocker();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                    System.out.println("Ummm.. I was sleeping here!");
                } finally {                
                    hideBlocker();
                }
            }
        };
        new Thread(runnable).start();
    }

    private void showBlocker() {
        // this executes off-EDT                
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                // this executes on-EDT
                blocker.setLocationRelativeTo(BlockingDialogDemo.this);
                blocker.setVisible(true);
            }
        });
    }

    private void hideBlocker() {
        // this executes off-EDT
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                // this executes on-EDT
                blocker.setVisible(false);
                timer.restart();
            }
        });
    }

    public static void main(String[] args) {
        // this is called off-EDT
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                // this is called on-EDT
                new BlockingDialogDemo().setVisible(true);
            }
        });
    }

}

答案 3 :(得分:0)

是的,有一些技巧可以使其正常工作。我们只是停用模态并手动禁用要使其不可点击的JFrame

private final static JDialog dialog; static {
        JOptionPane pane = new JOptionPane();
        pane.setOptions(new Object[]{}); // Removes all buttons
        dialog = pane.createDialog(frame, ""); // Create dialog with pane
        dialog.setModal(false); // IMPORTANT! Now the thread isn't blocked
        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
}

现在您可以像这样使用它:

dialog.setVisible(true);
frame.setEnabled(false);
// Logic
dialog.setVisible(false);
frame.setEnabled(true);

答案 4 :(得分:-1)

这对我有用......有时候:

public class NonBlockingModalDialogDemo extends JFrame{

    JButton btnDoIt;

    public NonBlockingModalDialogDemo() {
        setTitle("NonBlockingModalDialog Demo");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300,300);
        setLayout(new FlowLayout());

        btnDoIt = new JButton("Non-Blocking Notify");
        btnDoIt.addActionListener( new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent arg0) {
                JDialog asyncDialog = createNonBlockingModalDialog("Please wait while we do some work", "Please wait");

                doWork(50);
                //Once your done, just dispose the dialog to allow access to GUI
                asyncDialog.dispose();
            }

        });

        this.add(btnDoIt);
    }

    private JDialog createNonBlockingModalDialog(String message, String title)
    {
        final JDialog dialog = new JDialog();
        dialog.setLayout(new FlowLayout());
        dialog.add(new JLabel(message));
        dialog.setTitle(title);
        dialog.setModal(true);
        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
        dialog.setAlwaysOnTop(true);
        dialog.pack();

        Runnable dialogDisplayThread = new Runnable() {
            public void run() {
                dialog.setVisible(true);
            }};

        new Thread(dialogDisplayThread).start();

        //Need to wait until dialog is fully visible and then paint it
        //or else it doesn't show up right
        while(!dialog.isVisible()){/*Busy wait*/}
        dialog.paint(dialog.getGraphics());

        return dialog;
    }

    private void doWork(int amount) {
        for(int i = 0; i < amount; i++)
        {
            System.out.println("Doing work step number " + i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {}
        }

        System.out.println("done");
    }

    public static void main(String[] args) {
        new NonBlockingModalDialogDemo().setVisible(true);
    }
}

我真的不喜欢它有一个忙碌的等待来检查对话框是否可见,但到目前为止我还没有找到解决方法。无论如何,忙碌的等待不应该花很长时间,所以这真的不重要。

编辑: 我做了一些与此非常相似的事情,出于某种原因,在某些机器上,有时候,它只会在没有显示对话框的情况下永久阻止。

我还没有想出根本原因,但这让我得出结论,所有说“永远不会在事件调度线程之外修改GUI”的人可能会有所作为。

或许不是试图继续你在EDT上做的工作,也许你应该尝试这样的事情: https://stackoverflow.com/a/4413563/2423283 它使用SwingWorker生成新线程,然后允许您在完成后更新GUI组件。