【问题标题】:Binding objects in JavaFX在 JavaFX 中绑定对象
【发布时间】:2021-03-22 23:44:06
【问题描述】:

我很困惑如何使用对象绑定将 ObjectProperty 绑定到另一个对象。根据我在 javaFX 文档中阅读和理解的内容,这个 MCVE 应该输出 20,但它不起作用。输出即将变为 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();
}

根据我的理解,由于我调用了 bind(new SimpleObjectProperty(a.b)),所以每次 a.b 的值发生变化时,绑定就会失效,然后在稍后的某个时间,它使用 computeValue() 方法 impl 来分配它更新价值。

但看起来无论分配给它的第一个值是什么,即使在更改数据之后也不会改变。我在这里想念什么?我怎样才能使这个相同的例子工作?

【问题讨论】:

    标签: java debugging javafx


    【解决方案1】:

    您的代码中的问题是,您没有更改属性,而只是更改了基础数据。为了让 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.
    

    这在所有 JavaFX 控件中也是如此。看看例如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(); }
    

    所以每个 setter 都会设置属性。然后,您可以将该属性绑定到另一个属性(或使用addListener 添加一个侦听器以对更改做出反应)。

    【讨论】:

    • 所以你的意思是我需要更改我放在绑定方法中的 SimpleObjectProperty 对象以更改值?如果有怎么办?我在初始化绑定时尝试这样做:SimpleObjectProperty property = new SimpleObjectProperty(a.b);c.c.bind(new ObjectBindingImpl(a, property));property.set(new B(20)); 但结果仍然是 10。
    【解决方案2】:

    我的解释或多或少类似于@Maran23。您可以使绑定仅在可观察属性之间起作用。

    • 在您提供的示例中,绑定在 C.c 和 Binding 类中的“新 SimpleObjectProperty”实例之间。

    • 您正在更新 a.b 值,它不是可观察的属性。

    • 要获得 C.c 中反映的值,应更新“new SimpleObjectProperty”中的值。这在您的示例中是不可能的,因为实例是动态创建的,并且没有更新它的参考。

    • 因此,为了使您的示例正常工作,请为您在 ObjectBindingImpl 中创建的可观察属性创建一个引用,并确保更新此可观察属性值。

    我还想更正您关于

    的一个假设

    "...然后一段时间后,它使用 computeValue() 方法 impl 为其分配更新的值"

    它不会在某个随机时间更新。仅当您显式调用可观察属性的“get”方法时,它才会调用 computeValue。在调用 getter 之前,可观察属性将处于“无效”状态。

    请在下面的演示中找到我提到的更改。另请注意,还有许多其他有效的方法可以让绑定发生,但我试图用您提供的示例来回答您的实际操作。

    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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-17
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 2016-07-17
      • 2015-05-28
      相关资源
      最近更新 更多