【问题标题】:Java Swing - Updating the view from multiple threadJava Swing - 从多个线程更新视图
【发布时间】:2015-01-13 19:42:13
【问题描述】:

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

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);
    }
}

EDIT:Mission 是一个简单的类,属性为:int status

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

【问题讨论】:

  • 为什么不在你的 GUI 类中创建一个方法呢?例如,GUIClass.updateText()
  • 您可以使用 SwingWorker 作为 Blocks 和 UI 之间的代理,允许 SwingWorker 触发 PropertyChangeEvent 或发布更新...
  • @CaffeineToCode 你的意思是静态方法?我现在就试试... - MadProgrammer 看看编辑
  • 不一定是静态的,但是是一种方法。
  • @Cardella 当你在 MonitorPageController 中实现 Observer 时,在 update() 方法中你直接更新 ui 或者你使用 SwingUtilities.invokeLater() ??

标签: java multithreading swing logging


【解决方案1】:

更新 UI 调用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);
    }
}

【讨论】:

  • 我唯一会遇到的问题是它会将 UI 耦合到节点/块,这可能是不可取的。一个更好的解决方案是实现另一个观察者模式,它充当“状态”通知,这样实际就不会关心你对通知做了什么。这意味着你可以。使用 SwingWorker 的功能来同步 UI,因为 op 已经有一个 ;)
  • 正如 MadProgrammer 所说,这个解决方案让我在 SwingWorker 传递的 Block 类中拥有 View 的实例。我认为可能有更好的解决方案
【解决方案2】:

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

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

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

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 的实例。

现在里面的block类,当我想通知状态变化的时候,可以调用:

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

最后,MonitorPageController 中的 log() 方法调用 view 方法来更新组件……现在看来它可以工作了……

【讨论】:

    猜你喜欢
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-24
    • 1970-01-01
    相关资源
    最近更新 更多