简体   繁体   English

JavaFX 中的绑定对象

[英]Binding objects in JavaFX

I am very confused as how to bind an ObjectProperty to another Object using Object binding.我很困惑如何使用 Object 绑定将 ObjectProperty 绑定到另一个 Object 。 From what I have read & understood in javaFX documentations, this MCVE should output 20, but it is not working.根据我在 javaFX 文档中的阅读和理解,这个 MCVE 应该是 output 20,但它不起作用。 Output is coming to 0. Output 即将为 0。

// I tried to bind the attribute B's Integer attribute in class A to class C's SimpleIntegerProperty

package sample;

import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;

class ObjectBindingImpl extends ObjectBinding {
    private A a;

    public ObjectBindingImpl(A a) {
        this.a = a;
        bind(new SimpleObjectProperty<>(a.b));
    }

    @Override
    protected Object computeValue() {
        return a.b == null ? null : a.b.b;
    }
}
public class Main {

    public static void main(String[] args) {
        A a = new A();
        C c = new C();

        c.c.bind(new ObjectBindingImpl(a));
        a.b = new B(20); // Clearly I change the value to 20 here

        System.out.println(c.c.get()); // Expected output 20 as B.b = 20 but output returned is 10.
    }
}

class A {
    B b = new B(10); // Assigned it value 10.
}
class B {
    Integer b;
    B(int b) {
        this.b = b;
    }
}
class C {
    SimpleIntegerProperty c = new SimpleIntegerProperty();
}

As per my understanding, since I have called bind(new SimpleObjectProperty(ab)) so everytime the value of ab changes, the binding is invalidated, and then sometime later, it uses the computeValue() method impl to assign it updated value.根据我的理解,由于我调用了 bind(new SimpleObjectProperty(ab)) 所以每次 ab 的值发生变化时,绑定就会失效,然后某个时候,它使用 computeValue() 方法 impl 为其分配更新的值。

But it appears that whatever the first value assigned to it was does not change even after changing the data.但似乎无论分配给它的第一个值是什么,即使在更改数据之后也不会改变。 What am I missing here?我在这里想念什么? How can I make this same example work?我怎样才能使这个相同的例子工作?

The problem in your code is, that you don't change the property, but only the underlying data.您的代码中的问题是,您不更改属性,而只更改基础数据。 In order to make Property-Bindings recognise your change, you need to set the property:为了使 Property-Bindings 识别您的更改,您需要设置属性:

    A a = new A();

    SimpleObjectProperty aProperty = new SimpleObjectProperty<>(a);
    SimpleObjectProperty bProperty = new SimpleObjectProperty<>(a.b);

    System.out.println(aProperty.get()); // A, because we set it to a.

    aProperty.bind(bProperty);

    System.out.println(aProperty.get()); // null, because a.b is null (and we bound the value from bProperty now)

    bProperty.set(new B()); // Set the bProperty. This will update the aProperty as well, because it is bound to bProperty

    System.out.println(aProperty.get()); 
    // B, because we set bProperty to B, and as aProperty is bound to bProperty, this will change aProperty to it as well.

This is also done in all JavaFX Controls.这也在所有 JavaFX 控件中完成。 Just take a look in eg TableView :看看例如TableView

private ObjectProperty<ObservableList<S>> items = new SimpleObjectProperty<ObservableList<S>>(this, "items");
public final ObjectProperty<ObservableList<S>> itemsProperty() { return items; }
public final void setItems(ObservableList<S> value) { itemsProperty().set(value); }
public final ObservableList<S> getItems() {return items.get(); }

So every setter will set the property.所以每个 setter 都会设置属性。 You then can bind the property to another one (or add a listener with addListener to react to changes).然后,您可以将该属性绑定到另一个属性(或使用addListener添加一个侦听器以对更改做出反应)。

More or less my explanation is similar to @Maran23.我的解释或多或少类似于@Maran23。 You can make the bindings work between observable properties only.您可以使绑定仅在可观察属性之间起作用。

  • In the example you provided, the binding is between C.c and a "new SimpleObjectProperty" instance in the Binding class.在您提供的示例中,绑定在 C.c 和绑定 class 中的“新 SimpleObjectProperty”实例之间。

  • You are updating ab value, which is not an observable property.您正在更新 ab 值,这不是可观察的属性。

  • To get the value reflected in C.c, the value in "new SimpleObjectProperty" should be updated.要获得 C.c 中反映的值,应更新“new SimpleObjectProperty”中的值。 And this is not possible with your example because the instance is created on fly and there is no reference to update it.这在您的示例中是不可能的,因为该实例是动态创建的,并且没有更新它的参考。

  • So to make your example work, create a reference for the observable property you are creating in the ObjectBindingImpl and ensure you update this observable property value.因此,要使您的示例正常工作,请为您在 ObjectBindingImpl 中创建的可观察属性创建一个引用,并确保更新此可观察属性值。

I would also like to correct one of your assumptions about我还想纠正你的一个假设

" ...and then sometime later, it uses the computeValue() method impl to assign it updated value " ...然后一段时间后,它使用 computeValue() 方法 impl 为其分配更新的值

It is does not update at some random time.它不会在某个随机时间更新。 It calls the computeValue only when you explicitly call the "get" method of the observable property.仅当您显式调用可观察属性的“get”方法时,它才会调用 computeValue。 Untill the getter is called, the observable property will be in "invalid" state.在调用 getter 之前,可观察属性将处于“无效”state 中。

Please find below demo, with the changes I mentioned.请在下面的演示中找到我提到的更改。 Also note that there can be many other efficient ways to let the binding happen, but I am trying to answer your actual OP with the example you provided.另请注意,还有许多其他有效的方法可以让绑定发生,但我试图用您提供的示例来回答您的实际操作。

import javafx.beans.binding.ObjectBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;

public class ObjectBinding_Demo {

    public static void main(String[] args) {
        new ObjectBinding_Demo().init();
    }

    private void init() {
        A a = new A();
        C c = new C();

        ObjectBindingImpl binding = new ObjectBindingImpl(a);
        c.c.bind(binding);
        a.b = new B(20);
        binding.obj.setValue(a.b); // Update the observable property with the new value
        System.out.println("Value set in binding observable property..");
        System.out.println(c.c); // Output:: IntegerProperty [bound, invalid]
        System.out.println(c.c.get()); // Output:: 'Computing value...' string and then 20
        System.out.println(c.c); // Output:: IntegerProperty [bound, value: 20]

    }

    class ObjectBindingImpl extends ObjectBinding {
        private A a;
        ObjectProperty obj; // Observable property reference for future updating.

        public ObjectBindingImpl(A a) {
            this.a = a;
            obj = new SimpleObjectProperty(a.b);
            bind(obj);
        }

        @Override
        protected Object computeValue() {
            System.out.println("Computing value...");
            return a.b == null ? null : a.b.b;
        }
    }

    class A {
        B b = new B(10); // Assigned it value 10.
    }

    class B {
        Integer b;

        B(int b) {
            this.b = b;
        }
    }

    class C {
        SimpleIntegerProperty c = new SimpleIntegerProperty();
    }
}

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

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