簡體   English   中英

條件綁定沒有按預期工作

[英]Conditional binding doesn't work as expected

看看Layout -> initPanelSizeBinding() 問題是then()正在執行,即使panelProperty.get()null 難道我做錯了什么?

您可以自己嘗試一下,下面是完整的可重現示例。 (在 OpenJFX 15 上測試)

可重現的示例 -單擊此處(pastebin)

或者看看下面:

代碼:

主.java

public class Main {
 
    public static void main(String[] args) {
        Layout layout = new Layout();
        /*
        WARNING: Exception while evaluating binding
        java.lang.NullPointerException: Cannot invoke "Panel.getWidth()" because the return value of "javafx.beans.property.ObjectProperty.get()" is null
            at Layout.lambda$initPanelSizeBinding$0(Layout.java:20)
            at javafx.beans.binding.Bindings$6.computeValue(Bindings.java:358)
            at javafx.beans.binding.ObjectBinding.get(ObjectBinding.java:157)
            at javafx.beans.binding.ObjectExpression.getValue(ObjectExpression.java:49)
            at com.sun.javafx.binding.ExpressionHelper.addListener(ExpressionHelper.java:53)
            at javafx.beans.binding.ObjectBinding.addListener(ObjectBinding.java:77)
            at javafx.beans.binding.When$ObjectCondition.<init>(When.java:757)
            at javafx.beans.binding.When$ObjectConditionBuilder.otherwise(When.java:854)
            at Layout.initPanelSizeBinding(Layout.java:24)
            at Layout.<init>(Layout.java:12)
            at Main.main(Main.java:4)
         */
    }
 
}

布局.java

public final class Layout {
 
    public Layout() {
        panelSize.bind(initPanelSizeBinding(panel));
        // there's no need to do anything with panel, because it's an example
    }
 
    private ObjectBinding<Dimension2D> initPanelSizeBinding(ObjectProperty<Panel> panelProperty) {
        return Bindings
                .when(panelProperty.isNotNull())
                .then(Bindings.createObjectBinding(
                        () -> new Dimension2D(panelProperty.get().getWidth(), panelProperty.get().getHeight()),
                        Bindings.selectDouble(panelProperty, "width"),
                        Bindings.selectDouble(panelProperty, "height"))
                )
                .otherwise(new Dimension2D(150.0, 150.0));
    }
 
    //------Properties
 
    //panel
 
    private final ObjectProperty<Panel> panel = new SimpleObjectProperty<>
            (Layout.this, "panel", null);
 
    public ObjectProperty<Panel> panelProperty() {
        return panel;
    }
 
    public void setPanel(Panel value) {
        panel.set(value);
    }
 
    public Panel getPanel() {
        return panel.get();
    }
 
    //panelSize
 
    private final ReadOnlyObjectWrapper<Dimension2D> panelSize = new ReadOnlyObjectWrapper<>
            (Layout.this, "panelSize");
 
    public ReadOnlyObjectProperty<Dimension2D> panelSizeProperty() {
        return panelSize.getReadOnlyProperty();
    }
 
    public Dimension2D getPanelSize() {
        return panelSize.get();
    }
 
}

面板.java

public final class Panel {
 
    private final VBox rootNode;
 
    public Panel() {
        rootNode = new VBox();
        width.bind(rootNode.widthProperty());
        height.bind(rootNode.heightProperty());
    }
 
    public VBox getRootNode() {
        return rootNode;
    }
 
    //------Properties
 
    //width
 
    private final ReadOnlyDoubleWrapper width = new ReadOnlyDoubleWrapper
            (Panel.this, "width");
 
    public ReadOnlyDoubleProperty widthProperty() {
        return width.getReadOnlyProperty();
    }
 
    public double getWidth() {
        return width.get();
    }
 
    //height
 
    private final ReadOnlyDoubleWrapper height = new ReadOnlyDoubleWrapper
            (Panel.this, "height");
 
    public ReadOnlyDoubleProperty heightProperty() {
        return height.getReadOnlyProperty();
    }
 
    public double getHeight() {
        return height.get();
    }
 
}

至少從otherwise 15 開始, then和 other 綁定是熱切評估的1 我不確定他們是否應該1被熱切地評估,但他們是。 因此,盡管您可能正在以panelProperty.isNotNull()為條件,但您使用createObjectBinding創建的綁定仍然會嘗試計算該值,無論如何。 在這種情況下,最好放棄使用Bindings.when並在自定義綁定中自己實現邏輯:

private ObjectBinding<Dimension2D> initPanelSizeBinding(ObjectProperty<Panel> panelProperty) {
  DoubleBinding width = Bindings.selectDouble(panelProperty, "width");
  DoubleBinding height = Bindings.selectDouble(panelProperty, "height");
  return Bindings.createObjectBinding(
      () -> {
        Panel panel = panelProperty.get();
        if (panel == null) {
          return new Dimension2D(150.0, 150.0);
        }
        return new Dimension2D(width.get(), height.get());
      },
      panelProperty,
      width,
      height);
}

1.進一步研究,似乎條件綁定確實試圖變得懶惰。 不幸的是,條件綁定的行為將偵聽器添加到then observable 導致所述 observable 被驗證(並因此急切地評估)。 這是ExpressionHelper實現方式的結果,它調用observable.getValue()來驗證它。 我不明白為什么代碼會這樣做,特別是考慮到它是一個被添加的InvalidationListener應該是惰性監聽器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM