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

标签 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!");
            }
        });
    }
}

我的问题是,当 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() 进行不必要的调用,从而使我的代码变得困惑。

最佳答案

只有 AWTEvent 对象是从事件调度线程的上下文中处理的,所有其他类型的事件通常都是手动引发的(通常使用 for 循环 和列表注册听众的数量)。

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

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

如果您需要执行此操作(我会质疑原因),您应该将 firePropertyChange 包装在 invokeLater 调用中,以将其重新同步回 EDT .

同样,您可以使用 SwingWorker发布更改,以便在 EDT 中为您处理它们...

关于java - 从单独的线程修改基于 PropertyChangeEvent 的 Swing 组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18730971/

相关文章:

java - 我在 java 字符串中有 HTML,我想将其呈现为 PDF。有可用的 API 或引用吗?

java - 如果没有 Web 层并因此没有 HTTP session ,CDI 是否有意义?

c# - 从单独的线程访问表单的控件

c - 使用C中的宏为t数组赋值

java - 我正在尝试使用 Flowlayout 将 JPanel 添加到 JFrame,但仍然出现异常。我做错了什么?

java - 使用 OpenViewerFX 显示某些 PDF 时出错

java - Java Web 服务器所需的最低规范是什么?

java - 什么时候使用 ReentrantReadWriteLock 类的 readLock() 方法是安全的?

Java GUI 不显示在 Ubuntu 上的 Eclipse 中

java - 列表迭代类型不匹配