繁体   English   中英

将JavaFx属性绑定到多个可观察的对象

[英]Bind a JavaFx property to more than one observable

我正在编写一个JavaFx控件,该控件包含一个获取用户输入(例如TextField)的子控件。 主要组件具有一个属性,该属性表示文本的已解析表示形式,例如LocalDateTime。 用户输入内容时,应更新此属性,因此我将其绑定到孩子的value属性。 还可以通过绑定value属性从外部更改当前值,因此这必须是双向绑定才能自动更新子级。 直到客户端代码绑定到该属性,该控件才能正常工作。 以下代码显示了我的问题:

导入javafx.beans.property.SimpleIntegerProperty;

public class Playbook {

    // The internal control with a property p
    static class Child {
        public SimpleIntegerProperty p = new SimpleIntegerProperty();

        public void set(int i) {p.set(i);}
    }

    // My new control with a property value which is bound
    // bidirectionally to Child.p
    static class Parent {
        public Child a1;

        public SimpleIntegerProperty value = new SimpleIntegerProperty();

        public Parent() {
            a1 = new Child();

            value.bindBidirectional(a1.p);
        }
    }

    public static void main(String[] args) {
        Parent p = new Parent();

        // some client code wants to keep the 
        // value updated and thus binds to it
        SimpleIntegerProperty outside = new SimpleIntegerProperty();
        p.value.bind(outside);

        // simulate a change in the child control
        p.a1.p.set(10);         
    }
}

运行代码时,出现一个异常,即无法设置绑定属性:

Caused by: java.lang.RuntimeException: A bound value cannot be set.
    at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:143)
    at com.sun.javafx.binding.BidirectionalBinding$BidirectionalIntegerBinding.changed(BidirectionalBinding.java:467)

我确信这一定是一个普遍的问题,我只是没有看到明显的解决方案。 我正在使用ReactFx,因此欢迎使用纯JavaFx或ReactFx的任何解决方案。 实际代码使用Var.mapBidirectional在内部绑定Parent和Child属性。

我要实现的目标如下:1.如果outside的值更改,则应将其传播到p.value,然后传播到p.a1.p 2.如果p.a1.p更改,则应将其传播到p 。值

由此得出的结论是,Parent.value和Parent.a1.p始终是相同的(加上在映射中应用的某些转换),并且我使用双向投标映射。 外部可以独立更改,并且可以更改值,因此我使用单向绑定。

在理解JavaFx绑定不是我想的那样并且语义不允许这样做之后,我切换到ReactFx的 EventStream/Val/Var ReactFx的模型似乎更符合我的期望,这使我可以创建一个行为如下的系统:

  1. 如果外部值发生变化,则应将其传播到p.value,然后传播到p.a1.p
  2. 如果p.a1.p更改,则应将其传播到p.value

以下代码实现了这一点。 它使用两个分别双向绑定的Var ,因此其中一个的变化被馈送到另一个Var 从外部进行的更改被定义为一个EventStream ,它被馈送到Var之一。

import org.reactfx.EventStream;
import org.reactfx.EventStreams;
import org.reactfx.value.Var;

import javafx.beans.property.SimpleIntegerProperty;

public class Playbook {

    static class Child {
        public Var<Integer> p = Var.newSimpleVar(0);

        public void set(int i) {this.p.setValue(i);}
    }

    static class Parent {
        public Child a1;

        public Var<Integer> value = Var.newSimpleVar(0);

        public Parent() {
            this.a1 = new Child();

            this.value.bindBidirectional(this.a1.p);
        }
    }

    public static void main(String[] args) {
        Parent p = new Parent();

        // some client code wants to keep the
        // value updated and thus binds to it
        SimpleIntegerProperty outside = new SimpleIntegerProperty();

        // A SimpleIntegerProperty is not a Property<Integer> but a 
        // Property<Number> so we have to use map to translate to Integer
        EventStream<Integer> stream = EventStreams.valuesOf(outside).map(Number::intValue);

        stream.feedTo(p.value);

        // simulate a change in the child control
        p.a1.p.setValue(10);
        System.out.println( p.value.getValue() );
        System.out.println(p.a1.p.getValue() );
        System.out.println(outside.get());

        // feed new value from outside
        outside.set(42);

        System.out.println( p.value.getValue() );
        System.out.println(p.a1.p.getValue() );
        System.out.println(outside.get());
    }
}

程序运行并打印

10
10
0
42
42
42

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM