1

我有申请:

  • 一个用于用户输入的 JTextField,
  • 一个 JLabel 来回显示忙碌状态,
  • 一个用于打印搜索结果的 JTextArea。

我希望用户将文本写入文本字段,按 Enter 并查看结果。我有这样的听众:

private void searchForPattern(java.awt.event.ActionEvent evt) {
        textArea.setText("");
        busyLabel.setText("Searchnig ...");
        doSearch();
        busyLabel.setText("Idle");
    }

doSearch中有一个相当复杂的算法,它会打开大量 XML 文件并搜索给定的模式,这需要一段时间。只有在 doSearch 完成后,busyLabel 的文本才会更改为 Searching ...。doSearch 中没有第二个线程,只有大量的 IO 操作。

我怎样才能解决这个问题?

4

2 回答 2

4

您有一个经典的 Swing 并发问题(教程:Swing中的并发),其中 doSearch 正在占用 Swing 事件线程。由于这个线程是 Swing 进行所有绘画/绘图和与用户交互的地方,如果它被需要花费任何可察觉时间来完成的代码所束缚,整个应用程序将“冻结”,没有组件更新和所有用户交互被忽视。

解决方案:在后台线程上执行,例如 SwingWorker 对象提供的线程。done()在 SwingWorker 的方法中将“空闲”字符串设置到 JLabel 中。

IE,

private void searchForPattern(java.awt.event.ActionEvent evt) {
  textArea.setText("");
  busyLabel.setText("Searching ...");
  new SwingWorker<Void, Void>() {
     @Override
     protected Void doInBackground() throws Exception {
        doSearch();
        return null;
     }

     @Override
     protected void done() {
        busyLabel.setText("Idle");
     }
  }.execute();
}
于 2012-04-29T12:16:17.467 回答
1

您还可以使用 SwingUtilities 的invokeLater方法从应用程序线程更新 GUI swing 组件。

private void searchForPattern(java.awt.event.ActionEvent evt) {

  SwingUtilities.invokeLater(
    new Runnable(){
      public void run(){        
         textArea.setText("");
         busyLabel.setText("Searchnig ...");
      }
    }
  );

  doSearch();

  SwingUtilities.invokeLater(
    new Runnable(){
      public void run(){
         busyLabel.setText("Idle");
      }
    }
  );
}

编辑 PS:这里我假设你没有从 EDT 调用 searchForPattern() 函数,这意味着如果你从 ActionListener 调用它,你必须像这样调用它:

new Thread(
   new Runnable(){
      public void run(){
         searchForPattern(....)
      }
    }
  ).start();
于 2012-04-29T12:44:40.140 回答