0

In my code, I initialize a JDialog:

dialog = new JDialog( frame, "Login", true );
dialog.setContentPane( panel );
dialog.setDefaultCloseOperation( JDialog.HIDE_ON_CLOSE );
dialog.setBounds( new Rectangle( 50, 50, 500, 500 ) );

When a button in my main application is clicked, I show the dialog and then run an expensive method with the data I get from it:

dialogWrapper.show(); // Runs dialog.setVisible( true ) directly
LoginCredentials credentials = dialogWrapper.getCredentials(); // Gets data from dialog
try {
    SwingUtilities.invokeLater( new Runnable() {
        @Override
        public void run() {
            progressBar.setIndeterminate( true );
            mainWindow.getFrame().repaint();
            accountModel.login( credentials );
            System.out.println( "Successful login." );
            mainWindow.getFrame().revalidate();
            mainWindow.getFrame().repaint();
            progressBar.setIndeterminate( false );
        }
    } );
} catch ( Exception ex ) {
    // ...
}

My problem is that as soon as I click the button that runs dialog.setVisible( false ):

  • The dialog disappears
  • The frame completely freezes up (the progress bar state doesn't ever change)
  • After the message "Successful login." appears on the console, the frame is still frozen up
  • After around 10 seconds have passed, the frame finally repaints and all the status messages I call as part of accountModel.login() appear on it

How can I make my main window components responsive as the login code is running?

As you can see, I have the entire thing wrapped in a SwingUtilities.invokeLater() call, but that doesn't seem to be helping at all.

4

1 回答 1

2

如您所见,我将整个内容都包裹在 SwingUtilities.invokeLater() 调用中,

那就是问题所在。invokeLater() 将代码放在 EDT 上,这意味着在长时间运行的任务完成执行之前,GUI 无法重新绘制自身以响应事件。

Thread所以解决方案是为长时间运行的任务使用单独的,然后在Thread需要更新 GUI 时使用invokeLater().

或者,您也可以使用SwingWorker将为您创建线程,然后您可以将代码添加到done()SwingWorker 的方法以更新 GUI。

阅读 Swing 教程中关于并发的部分,了解更多关于Event Dispatch Thread (EDT)SwingWorker.

于 2016-01-05T03:24:00.513 回答