JavaFX:绑定到嵌套位置



我有一个包含一些VBoxLine s的Pane。我想将 Line s 的端点绑定到 VBox s 内部的"锚点"(基本上我想绑定到VBox中任意嵌套的Node的位置(,但我无法弄清楚什么值代表Node相对于顶部的位置Pane。我尝试过布局属性、翻译属性以及局部边界和父边界,但它们似乎都不起作用。我错过了什么?

(如果需要,我可以提供一个代码示例,但我认为它无助于更好地解释我的问题,因为我无法让它工作。

编辑:我忘了提到VBox可以在窗格中自由移动,这就是为什么我需要绑定线条的原因。

编辑:这里有一些来源显示我的进步。我可以得到正确的位置,但它没有约束力

public class Graph extends Application {
    private double startX;
    private double startY;
    private ObjectBinding<Bounds> bounds;
    private DoubleBinding tx;
    private DoubleBinding ty;
    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane pane = new Pane();
        Circle target = new Circle(5, Color.RED);
        VBox node = wrap(target);
        Line connector = new Line();
        bounds = Bindings.createObjectBinding(() -> {
                    Bounds nodeLocal = target.getBoundsInLocal();
                    Bounds nodeScene = target.localToScene(nodeLocal);
                    Bounds nodePane = pane.sceneToLocal(nodeScene);
                    return nodePane;
                },
                target.boundsInLocalProperty(),
                target.localToSceneTransformProperty(),
                pane.localToSceneTransformProperty()
        );
        connector.setStartX(0);
        connector.setStartY(0);
        tx = Bindings.createDoubleBinding(() -> bounds.get().getMinX(), bounds);
        ty = Bindings.createDoubleBinding(() -> bounds.get().getMinY(), bounds);
        connector.endXProperty().bind(tx);
        connector.endYProperty().bind(ty);
        connector.setStroke(Color.BLACK);
        pane.getChildren().add(node);
        pane.getChildren().add(connector);
        node.relocate(100, 100);
        primaryStage.setScene(new Scene(pane, 300, 300));
        primaryStage.show();
    }
    private VBox wrap(Circle target) {
        VBox node = new VBox(new Label("Node"), new StackPane(new Rectangle(50, 50, Color.GRAY), target));
        node.setOnMousePressed(event -> {
            Node source = (Node) event.getSource();
            startX = source.getBoundsInParent().getMinX() - event.getScreenX();
            startY = source.getBoundsInParent().getMinY() - event.getScreenY();
        });
        node.setOnMouseDragged(event -> {
            Node source = (Node) event.getSource();
            double offsetX = event.getScreenX() + startX;
            double offsetY = event.getScreenY() + startY;
            source.relocate(offsetX, offsetY);
        });
        return node;
    }
}

给定Pane pane中的任何Node node(意味着它有一个父级或间接祖先(,基本思想是

ObjectBinding<Bounds> boundsInPaneBinding = Bindings.createObjectBinding(() -> {
        Bounds nodeLocal = node.getBoundsInLocal();
        Bounds nodeScene = node.localToScene(nodeLocal);
        Bounds nodePane = pane.sceneToLocal(nodeScene);
        return nodePane ;
    }, node.boundsInLocalProperty(), node.localToSceneTransformProperty(), 
       pane.localToSceneTransformProperty());

boundsInPaneBinding是一个ObservableValue<Bounds>,它总是包含Pane坐标系中Node的边界。因此,您可以执行以下操作:

line.startXProperty().bind(Bindings.createDoubleBinding(
    () -> boundsInPaneBinding.get().getMinX(), 
    boundsInPaneBinding));

这里的棘手部分是确保绑定不会过早地被垃圾回收。(有关讨论,请参阅此处。首先,需要保留对绑定的引用:

private ObjectBinding<Bounds> boundsInPaneBinding ;

然后(由于我不太清楚的原因(,绑定实际上必须直接计算绑定属性:

boundsInPaneBinding = Bindings.createObjectBinding(() -> {
        Bounds nodeLocal = node.getBoundsInLocal();
        // note how this actually gets the value of localToSceneTransformProperty():
        Bounds nodeScene = node.getLocalToSceneTransform().apply(nodeLocal);
        Bounds nodePane = pane.sceneToLocal(nodeScene);
        return nodePane ;
    }, node.boundsInLocalProperty(), node.localToSceneTransformProperty(), 
       pane.localToSceneTransformProperty());

最新更新