[英]Repainting in a multithreaded environment
我正在开发一个带有大约十个不同数据源(例如统计/错误日志/...)的小程序。 每个数据源由单个网络连接更新,并通过观察者机制报告更新。 小程序具有显示部分数据的不同视图。 每个视图只对数据的某些部分感兴趣,并在必要的 Observables 上将自己注册为观察者。
视图(扩展的 JPanel)主要由标准的 swing 组件(例如 JLabels、JButton、...)组成。 视图中组件的某些属性取决于来自底层数据 model 的信息。
例子:
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
此逻辑在 StatisticPanel 的paintComponent()
方法中实现,而update()
方法只调用 repaint(),因为我不希望在 EDT 之外操作组件。
这是在多线程环境中更新 swing 组件的预期方式吗? 将 Runnable 与SwingUtitlies.invokeLater()
一起使用会更好吗? 有没有更好的方法来解决这个问题?
我第二个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.
}
编辑 2
另外,请看一下这个线程: check-if-thread-is-edt-is-necessary
repaint() 用于调用 Swing RepaintManger 反过来会安排组件的重绘,所以是的,直接调用 repaint 是可以的。 RepaintManager 将确保在 EDT 上完成所有重绘。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.