Threading with Swing

本文介绍如何在非UI线程中通过SwingUtilities.invokeLater()方法更新Swing组件,确保用户界面的更新在事件调度线程中进行。

Threading with Swing (ctd):
SwingUtilities.invokeLater()

In our introduction to threading with Swing,we said that any updates to the user interface must happen on theevent dispatch thread.So from any other thread— in practice, that means code thatisn'tcalled directly from an event handler— we must specifically arrange for our GUI updatecode, and generallyonly that code, to be called on the event dispatch thread.

So, supposing we have a button that launches a series of database queries.We dutifully start up a new thread so that our queries won't block the userinterface:

JButton b = new JButton("Run query");
b.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    Thread queryThread = new Thread() {
      public void run() {
        runQueries();
      }
    };
    queryThread.start();
  }
});




That was the easy bit. But now, from our query thread, we want to update a progress baror some other component showing the current progress to the user. How can we dothis if we're no longer in the event dispatch thread? Well, theSwingUtilitiesclass, which provides various useful little calls, includes a method calledinvokeLater(). This method allows us to post a "job" to Swing, whichit will then run on the event dispatch thread at its next convenience. Sohere is how to useSwingUtilities.invokeLater() from out runQueriesmethod:

// Called from non-UI thread
private void runQueries() {
  for (int i = 0; i < noQueries; i++) {
    runDatabaseQuery(i);
    updateProgress(i);
  }
}

private void updateProgress(final int queryNo) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      // Here, we can safely update the GUI
      // because we'll be called from the
      // event dispatch thread
      statusLabel.setText("Query: " + queryNo);
    }
  });
}

Here, statusLabel would be a JLabel or JTextField or something of that ilk—it doesn't matter terribly much. The point is: whatever GUI component it is, we mustmake sure that the code to update it is inside a call toinvokeLater().

There's a bit of awkward syntax that we've glossed over, but which it's importantto get used to for Swing programming generally. Essentially, we use ananonumous inner class to define our "job"— morespecifically, an implementation of theRunnable interface. Anonymousinner classes are a bit of syntactic shortcut. We could also have writtensomething like:

// Called from non-UI thread
private void runQueries() {
  for (int i = 0; i < noQueries; i++) {
    runDatabaseQuery(i);
    updateProgress(i);
  }
}

private void updateProgress(final int queryNo) {
  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
      // Here, we can safely update the GUI
      // because we'll be called from the
      // event dispatch thread
      statusLabel.setText("Query: " + queryNo);
    }
  });
}

But usually, it's a bit tedious to have to write a separate class definitionfor every pattern of update job. (Note that either way, they stillcompileto a different class.)

Application startup code

There's one place where it's very easy to forget that we needSwingUtilities.invokeLater(), and that's on application startup. Ourapplicationsmain() method will always be called by a special "main" thread that the VM starts up for us. And this main thread isnot theevent dispatch thread! So:

The code that initialises our GUImust also take place in aninvokeLater().

So our initial main() method should look something like this:

public class MyApplication extends JFrame {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MyApplication app = new MyApplication();
        app.setVisible(true);
      }
    });
  }

  private MyApplication() {
    // create UI here: add buttons, actions etc
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值