有没有办法在Swing中使用一个禁止任何gui活动的对话框,但同时又不会停止在设置为可见的线程上执行?
答案 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组件。