You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX中ObjectProperty为null时绑定依赖的解决方案咨询

How to create a nodeSize binding dependent on node's width/height without recreating the binding on node change?

I have an ObjectProperty<VBox> named node, and I want to create a nodeSize property that depends on it. Here's my current implementation:

public final class PropertyProblem { 
    public PropertyProblem() { 
        nodeSize.bind(initNodeSizeBinding(node)); 
    } 
    private ObjectBinding<Dimension2D> initNodeSizeBinding(ObjectProperty<VBox> nodeProperty) { 
        return Bindings.createObjectBinding(() -> { 
            if (nodeProperty.get() == null) { 
                return null; 
            } 
            VBox node = nodeProperty.get(); 
            ReadOnlyDoubleProperty widthProperty = node.widthProperty(), heightProperty = node.heightProperty(); 
            return new Dimension2D(widthProperty.get(), heightProperty.get()); 
        }, nodeProperty); 
    } 
    // node property 
    private final ObjectProperty<VBox> node = new SimpleObjectProperty<>(this, "node", null); 
    public ObjectProperty<VBox> nodeProperty() { 
        return node; 
    } 
    public void setNode(VBox val) { 
        node.set(val); 
    } 
    public VBox getNode() { 
        return node.get(); 
    } 
    // nodeSize property 
    private final ReadOnlyObjectWrapper<Dimension2D> nodeSize = new ReadOnlyObjectWrapper<> (this, "nodeSize"); 
    public ReadOnlyObjectProperty<Dimension2D> nodeSizeProperty() { 
        return nodeSize.getReadOnlyProperty(); 
    } 
    public Dimension2D getNodeSize() { 
        return nodeSize.get(); 
    } 
}

The issue with the initNodeSizeBinding() method is that when node is null, I can't include the node's width and height as dependencies. Right now, the binding only updates when node changes—not when the node's size changes. Is there a way to avoid recreating the binding every time the node property updates?


Great question! The core problem here is that your original binding only listens to changes in the nodeProperty itself, not the nested width and height properties of the VBox once it's assigned. You don't need to recreate the binding every time the node changes—here are two clean solutions:

Solution 1: Use Bindings.selectDouble for automatic nested property tracking

This is the simplest approach, leveraging JavaFX's built-in binding utilities to dynamically track nested properties even when the parent node is null or changes.

private ObjectBinding<Dimension2D> initNodeSizeBinding(ObjectProperty<VBox> nodeProperty) {
    // Track width and height properties of the node (handles null automatically)
    DoubleBinding widthBinding = Bindings.selectDouble(nodeProperty, "width");
    DoubleBinding heightBinding = Bindings.selectDouble(nodeProperty, "height");
    
    return Bindings.createObjectBinding(() -> {
        // Return null if node is null or size values are unavailable (NaN)
        if (nodeProperty.get() == null || Double.isNaN(widthBinding.get()) || Double.isNaN(heightBinding.get())) {
            return null;
        }
        return new Dimension2D(widthBinding.get(), heightBinding.get());
    }, widthBinding, heightBinding);
}

How this works:

  • Bindings.selectDouble creates a binding that first observes the nodeProperty. When a non-null VBox is set, it automatically starts observing that VBox's widthProperty and heightProperty.
  • If the node is set to null, widthBinding and heightBinding return NaN, which we check for to return null in the nodeSize binding.
  • This binding only needs to be created once—it will update whenever the node changes OR the node's size changes.

Solution 2: Custom Binding with Manual Listener Management

For more control (e.g., handling additional properties or custom logic when nodes are swapped), you can create a custom binding that manually manages listeners for the node's size properties.

private ObjectBinding<Dimension2D> initNodeSizeBinding(ObjectProperty<VBox> nodeProperty) {
    return new ObjectBinding<>() {
        private VBox currentNode;
        // Listeners to trigger recalculation when size changes
        private final InvalidationListener widthListener = obs -> invalidate();
        private final InvalidationListener heightListener = obs -> invalidate();

        {
            // Listen for changes to the node property
            nodeProperty.addListener((obs, oldNode, newNode) -> {
                // Clean up listeners from the old node
                if (oldNode != null) {
                    oldNode.widthProperty().removeListener(widthListener);
                    oldNode.heightProperty().removeListener(heightListener);
                }
                // Attach listeners to the new node
                if (newNode != null) {
                    newNode.widthProperty().addListener(widthListener);
                    newNode.heightProperty().addListener(heightListener);
                    currentNode = newNode;
                } else {
                    currentNode = null;
                }
                // Force a recalculation of the binding value
                invalidate();
            });
        }

        @Override
        protected Dimension2D computeValue() {
            if (currentNode == null) {
                return null;
            }
            return new Dimension2D(currentNode.getWidth(), currentNode.getHeight());
        }
    };
}

How this works:

  • The custom binding observes the nodeProperty directly. When the node changes, it removes listeners from the old node (if any) and adds listeners to the new node's size properties.
  • Whenever the node's size changes, the listeners trigger invalidate(), which forces the binding to recalculate its value.
  • Like the first solution, this binding only needs to be created once and handles all subsequent node changes and size updates.

Which approach to choose?

  • Use Solution 1 for simple cases where you just need to track nested properties—it's concise and leverages JavaFX's built-in utilities.
  • Use Solution 2 if you need more control over listener management, additional logic when nodes are swapped, or if you're tracking multiple properties beyond just width and height.

内容的提问来源于stack exchange,提问作者StackOverflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:39:50