如何使窗格保持在javafx中连接draggablenode的线上

问题描述 投票:0回答:1

我正在设计一个带有可拖动节点的图形结构的UI。在图中,我有一个名为relation的组件(它是一个窗格),它显示了两个节点之间的链接。我希望关系能够保持并在线中间移动。

当前的UI设计如下所示

而预期的一个是:

javafx line pane drag
1个回答
1
投票

修改线的末端坐标时,需要刷新节点的位置。为了避免每次布局传递多次触发计算,我建议从父级的layoutChildren方法执行此操作,但您也可以从侦听器到startXendY,...属性执行此操作。这将导致一些不必要的计算。

至于计算节点的位置:节点的中心需要与线的中点对齐,所以你需要为qazxsw poi求解下面的等式:

markTopLeft

Pane allowing for custom layout calculations

markTopLeft + (markWidth, markHeight) / 2 = (lineStart + lineEnd) / 2

markTopLeft = (lineStart + lineEnd - (markWidth, markHeight)) / 2

Usage

public class PostProcessPane extends Pane {

    private final Set<Node> modifiedChildren = new HashSet<>();
    private final Set<Node> modifiedChildrenUnmodifiable = Collections.unmodifiableSet(modifiedChildren);
    private final List<Consumer<Set<Node>>> postProcessors = new ArrayList<>();

    public List<Consumer<Set<Node>>> getPostProcessors() {
        return postProcessors;
    }

    private final ChangeListener listener = (o, oldValue, newValue) -> modifiedChildren.add((Node) ((ReadOnlyProperty) o).getBean());

    private void initListener() {
        getChildren().addListener((ListChangeListener.Change<? extends Node> c) -> {
            while (c.next()) {
                if (c.wasRemoved()) {
                    for (Node n : c.getRemoved()) {
                        n.boundsInParentProperty().removeListener(listener);
                    }
                }
                if (c.wasAdded()) {
                    for (Node n : c.getAddedSubList()) {
                        n.boundsInParentProperty().addListener(listener);
                    }
                }
            }
        });
    }

    public PostProcessPane() {
        initListener();
    }

    public PostProcessPane(Node... children) {
        super(children);
        initListener();

        for (Node n : children) {
            n.boundsInParentProperty().addListener(listener);
        }
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren();

        if (!modifiedChildren.isEmpty()) {
            for (Consumer<Set<Node>> processor : postProcessors) {
                processor.accept(modifiedChildrenUnmodifiable);
            }
            modifiedChildren.clear();
        }

    }

}
© www.soinside.com 2019 - 2024. All rights reserved.