Reputation: 401
If I understand correctly, when I modify a Swing component directly from another thread, that action should be placed on the EDT's event queue to prevent synchronization issues with the 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!");
}
});
}
}
My question is, do I need to follow this same idiom when the Swing component is not modified directly within the non-EDT thread, but instead by a PropertyChangeListener executing on the EDT that receives a PropertyChangeEvent from another thread?
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!");
}
}
It doesn't look like there's anything in PropertyChangeSupport that would make it inherently "Swing safe", but I don't want to clutter up my code with unnecessary calls to EventQueue.invokeLater() if they're not required.
Upvotes: 2
Views: 781
Reputation: 347184
Only AWTEvent
objects are processed from the context of the Event Dispatching Thread, all other types of events are generally raised manually (generally using a for-loop
and a list of registered listeners).
This means, in the context of your example, the property change event would actually be triggered outside of the EDT. Because most Swing components assume that they are being notified within the EDT, this is indeed dangerous.
Now, you could modify any of your PropertyChangeListener
s to check that they are being executed within the context of the EDT, but what you can't do is change how other registered listeners might work.
If you need to do this (I would question the reason's why), you should wrap the firePropertyChange
in an invokeLater
call to re-sync it back to the EDT.
Equally, you could use a SwingWorker
and publish
the changes so that they are processed
within the EDT for you...
Upvotes: 2