2013-07-23 24 views
0

在我的java应用程序中,我使用了swing来实现UI。有一个叫theButton按钮,这与一些IO操作如下时间步骤从事:java - 如何使用invokeLater与UI同步一些IO

  1. 按钮本来就具有文本“点击连接”
  2. 然后才连接操作开始我想要的theButton读取 “正在连接...”
  3. 那么IO操作得到启动
  4. 一次IO操作完成theButton现在读取“连接(点击断开连接)”。

    • 问题
    • 我使用下面的代码,但首先的按钮的文本不会更改为“连接中...”的IO开始之前!以及按钮doenst实际上在IO开始之前被禁用!我应该在这里做什么?

-

// theButton with text "Click to connect is clicked" 
javax.swing.SwingUtilities.invokeLater(new Runnable() { 
public void run() { 
theButton.setText("Trying to connect..."); 
theButton.setEnabled(false);// to avoid clicking several times! Some users cannot wait 
theButton.repaint(); 
// doing some IO operation which takes few seconds 
theButton.setText("connected (click to disconnect)"); 
theButton.setEnabled(true); 
theButton.repaint(); 
} 
}); 
+0

后台工作人员和异步事件。 – user2246674

回答

3

你的问题是在这里:

javax.swing.SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
    theButton.setText("Trying to connect..."); 
    theButton.setEnabled(false); 
    theButton.repaint(); 

    // doing some IO operation which takes few seconds // ********** 

    theButton.setText("connected (click to disconnect)"); 
    theButton.setEnabled(true); 
    theButton.repaint(); 
    } 
}); 
  • 标有*******评论的代码在运行EDT,将比分扳成了冰点你的应用程序和所有的绘画。
  • 改为使用SwingWorker在后台线程中运行代码。
  • 请注意,ActionListener中的代码不需要使用invokeLater(...),因为此代码默认情况下已在EDT上运行。
  • 也摆脱你的repaint()电话,因为他们不需要,他们不帮助。
  • 为您的SwingWorker添加一个PropertyChangeListener来监听它何时完成,然后您可以重置您的JButton。

而是做:

// code not compiled nor tested 
javax.swing.SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
    theButton.setText("Trying to connect..."); 
    theButton.setEnabled(false); 

    MySwingWorker mySwingWorker = new MySwingWorker(); 

    mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() { 
     // listen for when SwingWorker's state is done 
     // and reset your button. 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
     if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) { 
      theButton.setText("connected (click to disconnect)"); 
      theButton.setEnabled(true); 
     } 
     } 
    }); 

    mySwingWorker.execute(); 
    } 
}); 

// code not compiled nor tested 
public class MySwingWorker extends SwingWorker<Void, Void> { 
    @Override 
    public void doInBackground() throws Exception { 
    // doing some IO operation which takes few seconds 
    return null; 
    } 
} 

而且一定要阅读:Concurrency in Swing

+0

虽然,我有点好奇,为什么在“冻结”之前重新绘制没有更新UI(即使我一般建议不要这种方法)。我认为重绘是立竿见影的 - 或者有另一种类似的黑客来强制更新UI? - 对于这种特殊的黑客案例。 – user2246674

+0

@ user2246674:重绘将不起作用,因为当您调用它时,会在重绘管理器队列上排队重绘请求。经理在长时间运行流程关闭EDT之前没有时间处理请求。 –

+1

@HovercraftFullOfEels啊,对,这就是黑客的行为。'invokeLater(doBeforeBlockingWorkAndQueueRepaintAndQueueInvokeLaterForBlockingOperation);'* shudder *。 – user2246674