制作一个显示“请等待”的摇摆线程的JDialog [英] Make a swing thread that show a "Please Wait" JDialog
问题描述
问题是这样的:
我正在运行一个swing应用程序,在某个时刻对话框需要输入用户名和密码并按下ok。
我希望当用户按下ok时,swing应用程序按此顺序执行:
The problem is this:
I've a swing application running, at a certain point a dialog requires to insert username and password and to press "ok".
I would like that when the user press "ok" the swing application does in this order:
- 打开a请等待JDialog
- 进行一些操作(最终显示其他一些JDialog或JOptionPane)
- 当它完成操作关闭请等待JDialog
这是我在okButtonActionPerformed()中编写的代码:
This is the code that I wrote in the okButtonActionPerformed():
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
waitDialog.setVisible(true);
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
这段代码显然不起作用,因为当我在同一个线程中调用waitDialog时它会阻塞所有代码直到我不关闭它。
所以我尝试在不同的线程中运行它:
This code obviously doesn't works because when I call the waitDialog in the same thread it blocks all till I don't close it.
So I tried to run it in a different thread:
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {
//This class simply extends a JDialog and contains an image and a jlabel (Please wait)
final WaitDialog waitDialog = new WaitDialog(new javax.swing.JFrame(), false);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
waitDialog.setVisible(true);
}
});
... //Do some operation (eventually show other JDialogs or JOptionPanes)
waitDialog.dispose()
}
但这也不起作用,因为waitDialog不会立即显示,但只有在操作完成后才会显示他们的工作(当他们显示joption窗格时你已登录为。 ..)
But also this doesn't work because the waitDialog is not displayed immediately but only after that the operation completed their work (when they show a joption pane "You are logged in as...")
我还尝试使用invokeAndWait而不是invokeLater,但在这种情况下它会引发异常:
I also tried to use invokeAndWait instead of invokeLater but in this case it throws an exception:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
我该怎么办?
推荐答案
考虑使用SwingWorker进行后台工作,然后在SwingWorker的 done()
方法中关闭对话框,或者在添加到的PropertyChangeListener中关闭对话框(我的偏好) SwingWorker。
Consider using a SwingWorker to do your background work, and then closing the dialog either in the SwingWorker's done()
method or (my preference) in a PropertyChangeListener that is added to the SwingWorker.
例如,
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class PleaseWaitEg {
public static void main(String[] args) {
JButton showWaitBtn = new JButton(new ShowWaitAction("Show Wait Dialog"));
JPanel panel = new JPanel();
panel.add(showWaitBtn);
JFrame frame = new JFrame("Frame");
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ShowWaitAction extends AbstractAction {
protected static final long SLEEP_TIME = 3 * 1000;
public ShowWaitAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent evt) {
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>(){
@Override
protected Void doInBackground() throws Exception {
// mimic some long-running process here...
Thread.sleep(SLEEP_TIME);
return null;
}
};
Window win = SwingUtilities.getWindowAncestor((AbstractButton)evt.getSource());
final JDialog dialog = new JDialog(win, "Dialog", ModalityType.APPLICATION_MODAL);
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("state")) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
dialog.dispose();
}
}
}
});
mySwingWorker.execute();
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
JPanel panel = new JPanel(new BorderLayout());
panel.add(progressBar, BorderLayout.CENTER);
panel.add(new JLabel("Please wait......."), BorderLayout.PAGE_START);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(win);
dialog.setVisible(true);
}
}
注意:
- 关键概念是设置所有内容,添加PropertyChangeListener,运行SwingWorker,所有 显示模态对话框,因为一旦显示模态对话框,来自调用代码的所有代码流都被冻结(如您所知)。
- 为什么我更喜欢PropertyChangeListener来使用done方法(正如Elias在这里得到的体面回答所示,我已经投票了) - 使用监听器提供了更多的关注点分离,松耦合。通过这种方式,SwingWorker不必知道正在使用它的GUI代码。
这篇关于制作一个显示“请等待”的摇摆线程的JDialog的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!