Строка JavaFX между двумя кружками и центрирующим текстом в цикле - PullRequest
0 голосов
/ 10 ноября 2019

Я пытаюсь написать программу для бинарного дерева поиска, которая поместит кружки на панель в 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();
}

Мой вывод: Мой вывод Требуемый вывод: Желаемый вывод

1 Ответ

1 голос
/ 11 ноября 2019

Относительно позиционирования строки .. вы связали значения 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
  • Don 'не беспокоиться о расположении текста.

Это всего лишь мои взгляды, не уверен, что это поможет вам.

    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();
        }
    }
}
...