两个圆圈之间的JavaFX线,并在圆弧内居中放置文本

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

我正在尝试为二进制搜索树编写一个程序,该程序会将圆圈放在JavaFX的窗格中,然后将圆圈与直线连接起来,使其看起来像二进制搜索树。我可以使圆出现在窗格中,但是正在创建的线保持在顶部,并且不会从父圆的中心到新圆的中心。我也希望文本在圆圈内居中,但我也无法使其正常工作。我在下面将我的代码以及我的输出和所需的输出一起发布了。

public boolean addNode(T addMe) {
        boolean added = false;
        MyNode current = root;
        MyNode node = new MyNode(addMe, null, null);
        if (root == null) {
            root = node;
            added = true;
        } else {
            while (added != true) {
                if (addMe.compareTo(current.info) < 0) {
                    if (current.left == null) {
                        current.left =  new MyNode(addMe, null, null);
                        added = true;
                    } else {
                        current = current.left;
                    }
                } else {
                    if (current.right == null) {
                        current.right =  new MyNode(addMe, null, null);
                        added = true;
                    } else {
                        current = current.right;
                    }
                }
            }
        }
        node.label = new Text("" + addMe);
        node.label.setFont(new Font(16));
        node.circle = encircle(node.label, node);
        node.label.xProperty().bind(node.circle.centerXProperty());
        node.label.yProperty().bind(node.circle.centerYProperty());
        node.edge = new Line();
        if(node != root) {   
        node.edge.startXProperty().bind(current.circle.centerXProperty());
        node.edge.endXProperty().bind(node.circle.centerXProperty());
       }
        this.getChildren().add(node.edge);
        node.edge.toBack();

        node.circle.setOnMouseDragged(evt -> {
            double mouseX = evt.getX(),
                    mouseY = evt.getY();
            node.circle.setCenterX(mouseX);
            node.circle.setCenterY(mouseY);
        });
        this.getChildren().addAll(node.circle, node.label);
        return added;
    }

    private Circle encircle(Text text, MyNode node) {
        node.circle = new Circle();
        node.circle.setFill(Color.WHITE);
        final double PADDING = 10;
        node.circle.setRadius(getWidth(text) / 2 + PADDING);
        if (node == root) {
            node.circle.setStroke(Color.RED);
        } else {
            node.circle.setStroke(Color.BLACK);
        }
        return node.circle;
    }

    private int getWidth(Text text) {
        new Scene(new Group(text));
        text.applyCss();
        return (int) text.getLayoutBounds().getWidth();
    }

我的输出:My Output所需的输出:Desired Output

javafx geometry line center
1个回答
0
投票

关于行定位。您绑定了x值,却忘记了绑定y值。

node.edge.startYProperty().bind(current.circle.centerYProperty());
node.edge.endYProperty().bind(node.circle.centerYProperty());

关于文本的位置,您需要将文本移到边界的一半以将其定位到给定位置的中心。以下代码可能有效。

node.label.xProperty().bind(node.circle.centerXProperty().subtract(node.circle.radiusProperty().subtract(10))); // Your PADDING value
node.label.yProperty().bind(node.circle.centerYProperty().subtract(node.circle.radiusProperty().subtract(10))); // Your PADDING value

如果您提供一个最小的示例,我可以为您提供更准确的解决方案。

每个实现都有很多方法。由于以下原因,以下是我可以使用的一种方法:

  • 将类似的东西分组在一堂课中
  • 避免使用额外的Circle节点
  • 不要担心文本的位置。

这些只是我的观点,不确定这是否可以帮助您。

    import javafx.application.Application;
import javafx.beans.binding.DoubleBinding;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class BinarySearchLayoutDemo extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane root = new Pane();
        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        InfoNode node1 = buildAndAddNode(root, null, "345785", 100, 100);
        InfoNode node2 = buildAndAddNode(root, node1, "2356", 200, 200);
        InfoNode node3 = buildAndAddNode(root, node1, "589", 50, 200);
        InfoNode node4 = buildAndAddNode(root, node2, "478", 280, 300);
        InfoNode node5 = buildAndAddNode(root, node2, "25", 150, 300);
    }

    private InfoNode buildAndAddNode(Pane root, InfoNode parentNode, String text, double x, double y) {
        InfoNode node = new InfoNode(text);
        node.setPosition(x, y);
        root.getChildren().add(node);
        if (parentNode != null) {
            Line line = new Line();
            line.startXProperty().bind(parentNode.centerXProperty());
            line.startYProperty().bind(parentNode.centerYProperty());
            line.endXProperty().bind(node.centerXProperty());
            line.endYProperty().bind(node.centerYProperty());
            root.getChildren().add(line);
            line.toBack();
        }
        return node;
    }

    class InfoNode extends StackPane {
        private double PADDING = 8;
        private double x;
        private double y;

        public InfoNode(String txt) {
            Text text = new Text(txt);
            double size = getWidth(text) + (2 * PADDING);
            setStyle("-fx-shape:\"M 0 0 m -5, 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0\";-fx-border-color:black;-fx-border-width:1px;-fx-background-color:yellow;");
            setMinSize(size, size);
            getChildren().add(text);

            widthProperty().addListener((obs, old, val) -> setLayoutX(x - val.doubleValue() / 2));
            heightProperty().addListener((obs, old, val) -> setLayoutY(y - val.doubleValue() / 2));
        }

        public DoubleBinding centerXProperty() {
            return layoutXProperty().add(widthProperty().divide(2));
        }

        public DoubleBinding centerYProperty() {
            return layoutYProperty().add(heightProperty().divide(2));
        }

        public void setPosition(double x, double y) {
            this.x = x;
            this.y = y;
            setLayoutX(x - getWidth() / 2);
            setLayoutY(y - getHeight() / 2);
        }

        private double getWidth(Text text) {
            new Scene(new Group(text));
            text.applyCss();
            return text.getLayoutBounds().getWidth();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.