从单独的线程修改基于PropertyChangeEvent的Swing组件

时间:2013-09-11 00:43:43

标签: java multithreading swing

如果我理解正确,当我直接从另一个线程修改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()调用我的代码。

1 个答案:

答案 0 :(得分:2)

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

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

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

如果您需要这样做(我会质疑其原因),您应该将firePropertyChange包裹在invokeLater电话中,以便将其重新同步回EDT。

同样,您可以使用SwingWorkerpublish这些更改,以便它们在您的EDT中为processed ...