java swing挂起系统中的setvisible方法

java swing挂起系统中的setvisible方法,java,swing,visibility,swingworker,Java,Swing,Visibility,Swingworker,我有一个我目前正在开发的银行gui应用程序,我的jdialog的setvisible方法似乎有问题。在用户提取了有效金额后,我弹出一个简单的对话框,上面写着“交易进行中”。在我的dobackground方法中,我不断轮询以检查是否已收到事务。我试过使用swingworker,但我不明白为什么它不起作用。如果我删除setvisible调用,它工作正常,那么为什么setvisible会导致系统挂起?以下是我的jbutton mouselistener中的代码: SwingWorker<Stri

我有一个我目前正在开发的银行gui应用程序,我的jdialog的setvisible方法似乎有问题。在用户提取了有效金额后,我弹出一个简单的对话框,上面写着“交易进行中”。在我的dobackground方法中,我不断轮询以检查是否已收到事务。我试过使用swingworker,但我不明白为什么它不起作用。如果我删除setvisible调用,它工作正常,那么为什么setvisible会导致系统挂起?以下是我的jbutton mouselistener中的代码:

SwingWorker<String,Integer> worker = new SwingWorker<String,Integer>(){

  JDialog waitForTrans = new JDialog((JFrame)null,true);
  public String doInBackground() throws Exception {
     waitForTrans.add(new JLabel("Updating balance in system. Please Wait..."));
     waitForTrans.setMinimumSize(new Dimension(300,100));
     waitForTrans.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
     waitForTrans.setVisible(true);
     Bank.getInstance().sendTransaction(currentPin,"-"+withdraw);
     while(!Bank.getInstance().hasCompletedTransaction){

     }
     return null;

  }

  public void done(){
   try {
        this.get();
       } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {

        e.printStackTrace();
    }
    waitForTrans.setVisible(false);
    newField.setText(String.valueOf(Bank.getInstance().getAccountList().get(currentPin).getBalance()));
  }

 };
 worker.execute();
SwingWorker-worker=新的SwingWorker(){
JDialog waitForTrans=newjdialog((JFrame)null,true);
公共字符串doInBackground()引发异常{
waitForTrans.add(新的JLabel(“正在更新系统中的余额。请稍候…”);
waitForTrans.设置最小尺寸(新尺寸(300100));
waitForTrans.setDefaultCloseOperation(关闭时处理);
waitForTrans.setVisible(true);
Bank.getInstance().sendTransaction(currentPin,“-”+取款);
而(!Bank.getInstance().hasCompletedTransaction){
}
返回null;
}
公众假期结束(){
试一试{
这个。get();
}捕捉(中断异常e){
e、 printStackTrace();
}捕获(执行例外){
e、 printStackTrace();
}
waitForTrans.setVisible(false);
newField.setText(String.valueOf(Bank.getInstance().getAccountList().get(currentPin.getBalance());
}
};
worker.execute();

您正在显示一个模式对话框,因此在对话框关闭之前无法执行背景代码


在setVisible之后添加System.out.println(…)语句,您将看到它从未执行。

camickr给出了正确的答案。我想补充一点,您不能在事件调度线程之外修改UI(就像您在
#doInBackground
中所做的那样),Swing是单线程的,因此违反此规则可能会在UI中导致非常棘手的错误和奇怪的事情。

setVisible
是一种影响GUI的方法,会导致显示某些内容(并且,对于像您这样的模式对话框,阻塞直到对话框关闭)。除了在Swing event dispatch线程上调用外,不应调用它(与修改可见UI的所有其他内容一样)。您可以从运行在后台线程上的
SwingWorker
doInBackground
方法调用它

要解决此问题,需要将
waitForClose
对话框设置为
final
变量,该变量是在调用
SwingWorker
上的
execute
之前创建的,然后在启动worker后立即调用
setVisible
on

final JDialog waitForTrans = ...
// set up the dialog here

SwingWorker<String, Integer> worker = new SwingWorker<String, Integer>() {
  ...
};
worker.execute(); // start the background process

waitForTrans.setVisible(true); // show the dialog
final JDialog waitForTrans=。。。
//在这里设置对话框
SwingWorker worker=新SwingWorker(){
...
};
worker.execute();//启动后台进程
waitForTrans.setVisible(true);//显示对话框

您需要按此顺序执行,因为否则模式对话框将阻止您启动工作进程。

首先,建议在Swing事件调度线程中执行所有GUI更新,即使用
SwingUtilites

final JDialog waitForTrans = ...
// set up the dialog here

SwingWorker<String, Integer> worker = new SwingWorker<String, Integer>() {
  ...
};
worker.execute(); // start the background process

waitForTrans.setVisible(true); // show the dialog
其次,您的
JDialog
是模态的,因此会阻塞调用
setVisible(true)
方法的线程(在您的情况下是主线程,在下面的情况下是Swing事件调度线程)

我不是说下面的代码是完美的,但它应该让你走上正轨


final JDialog waitForTrans = new JDialog((JFrame) null, true);

SwingWorker worker = new SwingWorker() {

  public String doInBackground() throws Exception {
    Thread.sleep(5000);
    return null;
  }

  public void done() {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        waitForTrans.setVisible(false);
        waitForTrans.dispose();
      }
    });
  }

};

worker.execute();
SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    waitForTrans.add(new JLabel("Please Wait..."));
    waitForTrans.setMinimumSize(new Dimension(300, 100));
    waitForTrans.setVisible(true);
  }
});

希望这能有所帮助。

感谢您的快速响应!我对gui编程的这些方面仍然有点不太了解,但我现在大部分都明白了…了解Swing事件调度线程的工作方式以及如何以正确的方式使用它是Swing gui中最困难的部分。慢慢来,把它做好,这会帮您节省时间以后会有很多麻烦。done方法是在事件调度线程上执行的,因此我认为您不需要在该方法中使用SwingUtilities.invokeLater。请参见,此答案有一个竞态条件:在对话框设置为可见之前,可以调用done方法并销毁对话框。我可能遗漏了什么,我是foc主要是在OP的问题上使用,但从我的观点来看,您提到的竞争条件在这里是不可能的。在调用
done()之前,您可以通过这里的代码设置对话框可见
方法。原因是这两个操作都是在Swing事件调度线程中以串行方式完成的。使用
SwingUtilities.invokeLater(Runnable)
method以同步方式将操作发布到线程,即此处不可能出现您描述的竞争条件。您看到这种阻塞的java版本是什么?我们从java 6升级到java 8,可能会遇到这种行为。