Java Swing - 从多个线程更新视图

时间:2015-01-13 19:42:14

标签: java multithreading swing logging

这个问题可能会重复,因为我发现了很多类似的问题,但不是我的问题的答案:我需要从不同的SwingWorker更新我的SWING应用程序的视图。 我有一个带有JTextArea和JTable的View类,我需要在执行Threads期间更新它。视图还有一个启动按钮,可以启动所有线程。 控制器监听要单击的按钮,然后启动线程:

public class MonitorPageController {

    private MonitorPage monitorPage;
    private List<Mission> missions;

    class StartButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < missions.size(); i++) {
                MyWorker worker = new MyWorker(missions.get(i));
                worker.execute();
            }
        }
    }

}

然后我有管理模型的MyWorker类:​​

public class MyWorker extends SwingWorker<Integer, String> {

    private Mission m;

    //<dec>
    Block block1 = new Block();
    Block block2 = new block();
    Block block3 = new Block();
    Block block4 = new Block();

    public MyWorker(Mission mission) {
        this.m = mission;
    }

    @Override
    protected Integer doInBackground() throws Exception {
        //<exe>
        block1.addObserver(block2);
        block2.addObserver(block3);
        block3.addObserver(block4);
        block4.addObserver(block2);
        block1.update(null, m);

        return 4;
    }

}

最后我有Block类,我需要更新GUI(JTable和JTextArea):

public class Block extends Node implements Observer {


    public Mission run(Mission m) {
       m.setStatus(Mission.UNEXECUTED);

       // HERE I WANT TO NOTIGY THE VIEW OF THE CHANGE OF STATUS OF THE MISSION

       return m;
    } 

    @Override
    public void update(Observable o, Object arg) {
        Mission m = this.run((Mission) arg);
        setChanged();
        notifyObservers(m);
    }
}

编辑:Mission是一个简单的类,其属性为:int status

我已经尝试过另一个观察者模式:我将任务设置为observable,将MonitorPageController设置为观察者。然后在类Mission的状态的setter方法中添加了setChanged()和notifyObservers()方法。最后在Observer(MonitoPageController)中我实现了update()方法来调用视图并更新gui。 我喜欢这种方式,因为它干净且易于实现,但我现在不知道为什么在调用notifyObserver()后没有发生任何事情,所以我放弃了这个解决方案,即使它似乎是正确的

2 个答案:

答案 0 :(得分:1)

更新调用SwingUtilities.invokeLater()的用户界面:

public class Block extends Node implements Observer {


    public Mission run(Mission m) {
       m.setStatus(Mission.UNEXECUTED);       
       SwingUtilities.invokeLater(new Runnable(){  
          @Override        
          public void run(){
            //UPDATE UI HERE
          }
       });       
       return m;
    } 

    @Override
    public void update(Observable o, Object arg) {
        Mission m = this.run((Mission) arg);
        setChanged();
        notifyObservers(m);
    }
}

答案 1 :(得分:0)

我找到了一个可能的解决方案,也许有更好的想法,但现在可以使用: 在MonitorPageController中创建SwingWorker我也改变了传递MonitorPageController的istance的构造函数。

MyWorker worker = new MyWorker(misssions.get(i), this);

然后在MyWorker类中创建Block1,Block2时,...我将它们传递给MyWorker:

Block block1 = new Block(this);
Block block2 = new Block(this);
....

在同一个类(MyWorker)中,我创建了一个方法:

public void log(Mission m, String s) {
    controller.log(m, s);
}

Controller是创建worker的MonitorPageController的基础。

现在是内部块类,当我想通知状态变化时,我可以调用:

parentWorker.log(mission, "some string");

最后,MonitorPageController中的log()方法调用view方法来更新组件......到现在它似乎工作了......