2

私の理解が正しければ、Swing コンポーネントを別のスレッドから直接変更する場合、GUI との同期の問題を防ぐために、そのアクションを EDT のイベント キューに配置する必要があります。

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 スレッド内で直接変更されるのではなく、別のスレッドから PropertyChangeEvent を受け取る EDT で実行される 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