2011-05-24 114 views
3

我正在处理一个包含大约十个不同数据源(例如statistics/error-log/...)的小程序。每个数据源由单个网络连接更新并通过观察器机制报告更新。小程序具有不同的视图,显示部分数据。每个视图只对数据的某些部分感兴趣,并将其自己注册为必要Obserbles中的Observer。在多线程环境中重绘

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

例子:

StatisticPanel::paintComponent(Graphics g) { 
    clearStatisticButton.setEnabled(stat.hasEntries()); 
    minValueLabel.setText(stat.getMinValue()); 
    super.paintComponent(g); 
} 

这个逻辑在StatisticPanel的paintComponent()方法来实现和update()方法只是调用重绘(),因为我不想操纵EDT以外的成分。

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

回答

6

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

StatisticPanel::paintComponent(Graphics g) { 
    clearStatisticButton.setEnabled(stat.hasEntries()); 
    minValueLabel.setText(stat.getMinValue()); 
    super.paintComponent(g); 
} 

你在你的paintComponent方法非绘画方法(前两种方法),并作为1)你想不应该这种方法尽可能精简和快速,因此只有与绘画有关的代码,以及2)您不需要对此方法被调用时或何时调用这些方法进行抽象控制,因此非绘画相关的代码和程序逻辑不属于那里。出于这些原因,我强烈地敦促你将它们从那里分离出来,但应该与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. 
    } 

EDIT 2
另外,请看看在此线程:check-if-thread-is-edt-is-necessary

+1

+1深入查看代码。更改组件的属性将导致该组件再次被重新绘制。在某些情况下,这甚至可能会调用无限循环。 – camickr 2011-05-24 15:10:20

+0

解决这个问题是否有最佳实践?因为如果我理解你是正确的,Swingutilties.invokeLater方法在不执行paintComponent()代码中的程序逻辑的意义上更好,但也有可能导致无限循环。 – tfk 2011-05-24 15:27:06

+0

@tfk:参见**编辑1 **和**编辑2 ** – 2011-05-24 15:44:57

4

repaint()用于调用Swing RepaintManger,它将调度组件的重绘,所以可以直接调用重绘。 RepaintManager将确保所有重新绘制都在EDT上完成。