由于众所周知的原因,一般只有一个线程操作UI。对于多线程程序,怎么让工作线程去操作UI呢?在C++里,可以很方便地利用Windows消息,sendMessage和postMessage。在C#中,MSDN中也给出了用委托的方法。那Java中呢?
Java中观察者模式非常常见。跨线程操作UI也可以用观察者模式来实现。UI线程作为观察者,当工作线程有“动静”时,主动通知UI线程。
- import java.util.Observable;
- import java.util.Observer;
-
- public class MyAction extends Observable{
-
- public void test(){
- this.setChanged();
- this.notifyObservers();
-
- }
-
- }
被观察的对象“MyAction”通过test方法来通知观察者。MyAction应该在工作线程中。
- public class MainFrame extends JFrame implements Observer {
-
- @Override
- protected void frameInit() {
-
- super.frameInit();
- this.setLayout(null);
- JButton jb = new JButton("test");
- jb.setSize(100, 100);
- jb.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
-
- Thread t = new Thread(){
-
- @Override
- public void run() {
-
- MyAction action = new MyAction();
- //注册观察者
- action.addObserver(MainFrame.this);
- try {
- this.sleep(5000);
- } catch (InterruptedException e) {
-
- e.printStackTrace();
- }
- action.test();
- }
-
- };
- t.start();
- }
- });
- this.add(jb);
- }
-
-
-
-
- public static void main(String[] args) {
-
- MainFrame f = new MainFrame();
- f.setVisible(true);
- f.setDefaultCloseOperation(EXIT_ON_CLOSE);
- f.setSize(200, 200);
-
- }
-
- @Override
- public void update(Observable o, Object arg) {
-
- JOptionPane.showMessageDialog(null, "message");
-
- }
-
- }
观察者收到通知时,update方法就会被调用,在这个方法里更新UI即可。
纠错:
这种方法不能实现跨线程操作UI。测试方法,在update方法中获取Thread.currentThread().getId(),发现是非UI线程的ID。看了Observable的代码,确实没有跨线程的内容。
不过下述JComponent方法是安全的,可以从任何线程调用:repaint()、revalidate()、和invalidate()。(repaint()和revalidate()方法为事件派发线程对请求排队,并分别调用paint()和validate()方法。invalidate()方法只在需要确认时标记一个组件和它的所有直接祖先。)所以,可以重写这些方法,来更新UI。
另外,一般也不能使用Timer来主动获取工作线程的数据,因为Timer运行在其它线程上。
本文转自 dogegg250 51CTO博客,原文链接:http://blog.51cto.com/jianshusoft/691372,如需转载请自行联系原作者