如果我理解正确,当我直接从另一个线程修改Swing组件时,该操作应放在EDT的事件队列中,以防止与GUI同步问题:
public class SwingFrame extends JFrame {
private JTextField _textField;
public SwingFrame() {
_textField = new JTextField();
Thread thread = new Thread(new SomeRunnable(_textField));
thread.start();
}
}
public class SomeRunnable implements Runnable {
private final JTextField _textField;
public SomeRunnable(final JTextField textField) {
_textField = textField;
}
@Override
public void run() {
// _textField.setText("Goodbye, Swing!"); /* wrong */
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
_textField.setText("Hello, Swing!");
}
});
}
}
我的问题是,当在非EDT线程中没有直接修改Swing组件时,是否需要遵循同样的习惯用法,而是在EDT上执行的PropertyChangeListener从另一个线程接收PropertyChangeEvent?
public class SwingFrame extends JFrame implements PropertyChangeListener {
private JTextField _textField;
public SwingFrame() {
_textField = new JTextField();
Thread thread = new Thread(new SomeRunnable());
thread.start();
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("text")) {
_textField.setText(String.valueOf(evt.getNewValue()));
}
}
}
public class SomeRunnable implements Runnable {
private final PropertyChangeSupport _propertyChangeSupport;
public SomeRunnable() {
_propertyChangeSupport = new PropertyChangeSupport(this);
}
@Override
public void run() {
// Ok? Or wrap in EventQueue.invokeLater()?
_propertyChangeSupport.firePropertyChange("text", null, "Hello, Swing!");
}
}
看起来PropertyChangeSupport中没有任何内容可以使其本身“Swing安全”,但如果不需要,我不希望用不必要的EventQueue.invokeLater()调用我的代码。
答案 0 :(得分:2)
仅从事件调度线程的上下文处理AWTEvent
个对象,所有其他类型的事件通常都是手动引发的(通常使用for-loop
和已注册的侦听器列表)。
这意味着,在您的示例的上下文中,属性更改事件实际上将在EDT之外触发。因为大多数Swing组件都假设他们在EDT中被通知,这确实很危险。
现在,您可以修改任何PropertyChangeListener
以检查它们是否在EDT的上下文中执行,但您不能做的是更改其他注册的方式听众可能会工作。
如果您需要这样做(我会质疑其原因),您应该将firePropertyChange
包裹在invokeLater
电话中,以便将其重新同步回EDT。
同样,您可以使用SwingWorker
和publish
这些更改,以便它们在您的EDT中为processed
...