在多线程环境中重新绘制

tfk*_*tfk 3 java applet swing multithreading event-dispatch-thread

我正在开发一个包含大约十个不同数据源的applet(例如statistics/error-log/...).每个数据源由单个网络连接更新,并通过观察器机制报告更新.applet具有不同的视图,可以显示部分数据.每个视图只对数据的某些部分感兴趣,并在必要的Observables中将其自身注册为Observer.

视图(扩展的JPanels)主要由标准的摆动组件组成(例如JLabel,JButton,......).视图中组件的某些属性取决于基础数据模型中的信息.

例:

StatisticPanel::paintComponent(Graphics g) {
  clearStatisticButton.setEnabled(stat.hasEntries());
  minValueLabel.setText(stat.getMinValue());
  super.paintComponent(g);
}
Run Code Online (Sandbox Code Playgroud)

这个逻辑paintComponent()在StatisticPanel 的方法中实现,update()方法只调用repaint(),因为我不想操纵EDT之外的组件.

这是在多线程环境中更新swing组件的预期方法吗?使用Runnable更好SwingUtitlies.invokeLater()吗?这个问题有更好的方法吗?

Hov*_*els 6

我是第二个camickr的建议,但关于这段代码:

StatisticPanel::paintComponent(Graphics g) {
  clearStatisticButton.setEnabled(stat.hasEntries());
  minValueLabel.setText(stat.getMinValue());
  super.paintComponent(g);
}
Run Code Online (Sandbox Code Playgroud)

你的paintComponent方法中有非绘制方法(前两个方法),这不应该是1)你希望这个方法尽可能精简和快速,因此只有绘画相关的代码,2)你没有aboslute控制何时调用这个方法,或者甚至调用它,因此非绘画相关的代码和程序逻辑不属于那里.出于这些原因,我强烈建议你将它们从那里取出,但是应该与paintComponent分开调用,但与EDT上的大多数Swing代码一样.

编辑1
我不是专业人士,但如果你给StaticPanel一个类似的方法怎么样:

   public void doMyUpdate() {
      if (SwingUtilities.isEventDispatchThread()) {
         clearStatisticButton.setEnabled(stat.hasEntries());
         minValueLabel.setText(stat.getMinValue());
      } else {
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               clearStatisticButton.setEnabled(stat.hasEntries());
               minValueLabel.setText(stat.getMinValue());
            }
         });
      }
      repaint(); // if the paintComponent method has more than just a super call.
   }
Run Code Online (Sandbox Code Playgroud)

编辑2
另外,请看一下这个帖子:check-if-thread-is-edt-is-necessary