Java 在多线程环境中重新绘制
我正在开发一个小程序,其中包含大约10个不同的数据源(例如统计/错误日志/…)。每个数据源由单个网络连接更新,并通过观察者机制报告更新。小程序具有显示部分数据的不同视图。每个视图只对数据的某些部分感兴趣,并将自己注册为必要观察点的观察者 视图(扩展JPanel)主要由标准swing组件(例如JLabel、JButton等)组成。视图中组件的某些属性取决于来自底层数据模型的信息 例如:Java 在多线程环境中重新绘制,java,multithreading,swing,applet,event-dispatch-thread,Java,Multithreading,Swing,Applet,Event Dispatch Thread,我正在开发一个小程序,其中包含大约10个不同的数据源(例如统计/错误日志/…)。每个数据源由单个网络连接更新,并通过观察者机制报告更新。小程序具有显示部分数据的不同视图。每个视图只对数据的某些部分感兴趣,并将自己注册为必要观察点的观察者 视图(扩展JPanel)主要由标准swing组件(例如JLabel、JButton等)组成。视图中组件的某些属性取决于来自底层数据模型的信息 例如: StatisticPanel::paintComponent(Graphics g) { clearStat
StatisticPanel::paintComponent(Graphics g) {
clearStatisticButton.setEnabled(stat.hasEntries());
minValueLabel.setText(stat.getMinValue());
super.paintComponent(g);
}
此逻辑在StatisticPanel的paintComponent()
方法中实现,而update()
方法只调用repaint(),因为我不想在EDT之外操作组件
这是在多线程环境中更新swing组件的预期方法吗?将Runnable与
swingutilities.invokeLater()一起使用是否更好?有更好的方法解决这个问题吗?repaint()用于调用Swing RepaintManger,它反过来将安排组件的重新绘制,因此可以直接调用repaint。RepaitManager将确保在EDT上完成所有重新绘制。我支持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
另外,请查看此线程:+1以深入了解代码。更改组件的属性将导致重新绘制该组件。在某些情况下,这甚至可能会调用无限循环。有解决此类问题的最佳实践吗?因为如果我理解您的意思是正确的,Swingutiles.invokeLater方法在不执行paintComponent()代码中的程序逻辑的意义上更好,但也有可能导致无限循环。@tfk:请参见编辑1和编辑2