JavaFX中现有javabean的异步绑定
我正在将现有的Swing项目迁移到JavaFX。该项目有许多使用PropertyChangeSupport的旧式JavaBean,这些都是在各种后台线程上更新的JavaFX中现有javabean的异步绑定,java,asynchronous,javafx,javafx-8,Java,Asynchronous,Javafx,Javafx 8,我正在将现有的Swing项目迁移到JavaFX。该项目有许多使用PropertyChangeSupport的旧式JavaBean,这些都是在各种后台线程上更新的 我想使用bean适配器(javafx.beans.property.adapter)连接新视图。但是,这会失败,因为模型没有在FX应用程序线程上更新 理想情况下,我希望保留更新模型的现有代码,而不是将其包装在Platform.runLater中 到目前为止,我的解决方案是使用我自己的类AsyncBinding,该类接受由beans适
- 我想使用bean适配器(javafx.beans.property.adapter)连接新视图。但是,这会失败,因为模型没有在FX应用程序线程上更新
- 理想情况下,我希望保留更新模型的现有代码,而不是将其包装在Platform.runLater中
- 有没有什么我不知道的内在方法
- 我可以采取更干净的方法吗
到目前为止,我的最佳解决方案
- 创建一个实用程序类AsyncBinding,它代理ObservalEvalue
- 监听底层的可观察对象,在正确的线程上发送给侦听器
公共类AsyncBinding实现ObservalEvalue{
私人可观察价值;
私有失效监听器失效监听器;
私有交换侦听器交换侦听器;
私有列表无效侦听器=新建ArrayList(
1);
private ListRelated(但不同)问题:。执行了类似的操作,但实现了完整的属性:
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);
}
}
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();
}
}