2

如果我理解正确,当我直接从另一个线程修改 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!");
            }
        });
    }
}

我的问题是,当 Swing 组件不是在非 EDT 线程中直接修改,而是通过在 EDT 上执行从另一个线程接收 PropertyChangeEvent 的 PropertyChangeListener 时,我是否需要遵循同样的习惯用法?

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() 的不必要调用来混淆我的代码。

4

1 回答 1

2

只有AWTEvent对象是从事件调度线程的上下文中处理的,所有其他类型的事件通常是手动引发的(通常使用一个for-loop和一个注册侦听器列表)。

这意味着,在您的示例上下文中,属性更改事件实际上将在 EDT 之外触发。因为大多数 Swing 组件都假定它们在 EDT 中得到通知,所以这确实很危险。

现在,您可以修改您的任何PropertyChangeListeners 以检查它们是否在 EDT 的上下文中执行,但您不能做的是更改其他已注册侦听器的工作方式。

如果您需要这样做(我会质疑原因),您应该将其包装firePropertyChange在一个invokeLater调用中以将其重新同步回 EDT。

同样,您可以使用 aSwingWorkerpublish更改,以便它们processed在您的 EDT 中......

于 2013-09-11T01:12:49.890 回答