【问题标题】:Asynchronous bindings to existing java beans in JavaFXJavaFX 中与现有 Java bean 的异步绑定
【发布时间】:2014-12-09 13:28:29
【问题描述】:

我正在将现有的 Swing 项目迁移到 JavaFX。该项目有很多使用 PropertyChangeSupport 的老式 Java bean,这些都在各种后台线程上更新。

  • 我想使用 bean 适配器 (javafx.beans.property.adapter) 来连接新视图。然而,这失败了,因为模型没有在 FX 应用程序线程上更新。

  • 理想情况下,我想保留更新模型的现有代码,而不是包装在 Platform.runLater 中

到目前为止,我的解决方案是使用我自己的 AsyncBinding 类,它接受由 bean 适配器创建的现有 ObservableValue,监听它,并在适当的线程上触发更改,但是不得不到处添加它感觉很混乱

  • 是否有任何我缺少的内置方法?
  • 我可以采取更清洁的方法吗?

典型视图

public class AsyncIssue extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        FooBean bean = new FooBean();
        TextField field = new TextField();

        field.textProperty().bind(
                JavaBeanIntegerPropertyBuilder.create().bean(bean).name("x")
                        .build().asString("%03d"));
        primaryStage.setScene(new Scene(new VBox(field)));
        primaryStage.show();

        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            try {
                // simulate background work
                bean.setX(bean.getX() + 1);
            } catch (Throwable e) {
                // Executors consume exception by default
                e.printStackTrace();
                throw e;
            }
        }, 0, 1, TimeUnit.SECONDS);

    }
}

典型的豆子

public class FooBean {
    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    public static final String PROPERTY_X = "x";
    private int x;
    public int getX() {
        return x;
    }
    public void setX(int x) {
        int oldValue = this.x;
        this.x = x;
        pcs.firePropertyChange(PROPERTY_X, oldValue, x);
    }
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        pcs.removePropertyChangeListener(listener);
    }
}

【问题讨论】:

标签: java asynchronous javafx javafx-8


【解决方案1】:

目前为止我最好的解决方案

  • 创建一个代理 ObservableValue 的实用程序类 AsyncBinding
  • 监听底层的 observable,在正确的线程上分派给监听器。

用法

field.textProperty().bind(
        AsyncBinding.bind(JavaBeanIntegerPropertyBuilder.create()
                .bean(bean).name("x").build().asString("%03d")));

异步绑定

public class AsyncBinding<T> implements ObservableValue<T> {

    private ObservableValue<T> value;
    private InvalidationListener invalidationListener;
    private ChangeListener<T> changeListener;
    private List<InvalidationListener> invalidationListeners = new ArrayList<InvalidationListener>(
            1);
    private List<ChangeListener<? super T>> changeListeners = new ArrayList<ChangeListener<? super T>>(
            1);

    public static <T> ObservableValue<T> bind(ObservableValue<T> toWrap) {
        return new AsyncBinding<T>(toWrap);
    }

    private AsyncBinding(ObservableValue<T> value) {
        this.value = value;
        invalidationListener = new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                Runnable fire = () -> {
                    synchronized (invalidationListeners) {
                        for (InvalidationListener listener : invalidationListeners) {
                            listener.invalidated(observable);
                        }
                    }
                };
                if (Platform.isFxApplicationThread()) {
                    fire.run();
                } else {
                    Platform.runLater(fire);
                }
            }
        };
        value.addListener(invalidationListener);

        changeListener = new ChangeListener<T>() {
            @Override
            public void changed(ObservableValue<? extends T> observable,
                    T oldValue, T newValue) {
                Runnable fire = () -> {
                    synchronized (changeListeners) {
                        for (ChangeListener<? super T> listener : changeListeners) {
                            listener.changed(observable, oldValue, newValue);
                        }
                    }
                };
                if (Platform.isFxApplicationThread()) {
                    fire.run();
                } else {
                    Platform.runLater(fire);
                }
            }
        };

        value.addListener(changeListener);
    }

    @Override
    public void addListener(InvalidationListener listener) {
        invalidationListeners.add(listener);
    }

    @Override
    public void removeListener(InvalidationListener listener) {
        invalidationListeners.remove(listener);
    }

    @Override
    public void addListener(ChangeListener<? super T> listener) {
        changeListeners.add(listener);
    }

    @Override
    public void removeListener(ChangeListener<? super T> listener) {
        changeListeners.remove(listener);
    }

    @Override
    public T getValue() {
        return value.getValue();
    }
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 2014-01-09
  • 2017-05-29
  • 1970-01-01
相关资源
最近更新 更多