3

我正在开发一个带有大约十个不同数据源(例如统计/错误日志/...)的小程序。每个数据源由单个网络连接更新,并通过观察者机制报告更新。小程序具有显示部分数据的不同视图。每个视图只对数据的某些部分感兴趣,并在必要的 Observables 上将自己注册为观察者。

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

例子:

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

此逻辑在paintComponent()StatisticPanel 的方法中实现,并且这些update()方法只调用 repaint(),因为我不希望在 EDT 之外操作组件。

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

4

2 回答 2

6

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

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

您的 paintComponent 方法(前两种方法)中有非绘画方法,这不应该是 1)您希望此方法尽可能精简和快速,因此只有与绘画相关的代码,以及 2)您无法绝对控制何时调用此方法或即使调用此方法,因此非绘画相关的代码和程序逻辑不属于其中。出于这些原因,我强烈建议您将它们从那里删除,而是应该在 EDT 上与paintComponent 分开调用,但与大多数 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.
   }

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

于 2011-05-24T15:01:47.253 回答
4

repaint() 用于调用 Swing RepaintManger,它反过来会安排组件的重绘,所以是的,直接调用 repaint 是可以的。RepaintManager 将确保在 EDT 上完成所有重绘。

于 2011-05-24T14:59:17.720 回答