在多线程环境中重绘

发布于 2024-11-09 07:09:39 字数 669 浏览 4 评论 0原文

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

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

示例:

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

此逻辑在 StatisticPanel 的 paintComponent() 方法中实现,而 update() 方法仅调用 repaint(),因为我不想操纵EDT 之外的组件。

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

i am working on an applet with around ten different datasources(e.g. statistics/error-log/...). Each datasource is updated by a single network connection and reports updates via the observer mechanism. The applet has different views which display parts of the data. Every view is only interested in some parts of the data and registers itself as an Observer at the necessary Observables.

The views(extended JPanels) mostly consist of standard swing components (e.g. JLabels, JButton, ...). Some attributes of the components in the views depend on information from the underlying data model.

Example:

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

This logic is implemented in the paintComponent() method of the StatisticPanel and the update() methods just calls repaint(), because I didn't want the manipulate the components outside of the EDT.

Is this the intended way of updating swing components in a multi-threaded environment? Is it better to use a Runnable with SwingUtitlies.invokeLater()? Are there better approaches for this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

宛菡 2024-11-16 07:09:39

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

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

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

编辑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 是必要的

I second camickr's recommendations, but regarding this code snippet:

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

You have non-painting methods in your paintComponent method (the first two methods), and that shouldn't be as 1) you want this method to be as lean and fast as possible and thus have only painting-related code, and 2) you do not have aboslute control of when this method is called or even if it is called, and so non-painting related code and program logic does not belong in there. For these reasons, I strongly urge you to get them out of there, but instead should be called separate from paintComponent, but as with most Swing code, on the EDT.

EDIT 1
I'm not a professional, but how about if you gave your StaticPanel a method similar to this:

   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
Also, please have a look at this thread: check-if-thread-is-edt-is-necessary

晨曦慕雪 2024-11-16 07:09:39

repaint() 用于调用 Swing RepaintManger,后者将安排组件的重绘,所以直接调用 repaint 就可以了。 RepaintManager 将确保所有重绘都在 EDT 上完成。

repaint() is used to invoke the Swing RepaintManger which in turn will schedule the repainting of the component, so yes it is ok to just invoke repaint directly. The RepaintManager will make sure all repainting is done on the EDT.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文