使用javafx在运行时定义对象位置

时间:2017-10-04 10:46:58

标签: java eclipse javafx graph

我正在使用javaFX创建一个应用程序。该应用程序包括从用户创建一种“图形”。 用户通过按钮创建一个节点(由带有JAVAFX图的圆圈创建)并将其与变量相关联,重复该过程,创建另一个节点,依此类推。现在我需要弄清楚如何在特别保留的空间内定义节点位置。显然,在创建节点之后,通过另一个按钮,用户创建与节点相关联的弧(由连接两个节点的线创建),从而定义图形。 我的问题是我不明白如何在我的图表中指出将作为弧线的线的位置。

请帮助我。我不是很有经验,我正在努力解决这个问题。

1 个答案:

答案 0 :(得分:0)

首先,你需要告诉我们你的“预留空间”是什么?如果它是Canvas,那么你可以使用Canva的GraphicsContext绘制形状。

Canvas canvas = new Canvas(300, 250);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.fillOval(10, 60, 30, 30);
gc.fillArc(10, 110, 30, 30, 45, 240, ArcType.OPEN);

否则,如果您在包含布局的窗格内工作,则需要知道组件是否受管理。例如,在Pane或AnchorPane内部,节点的自动布局被禁用,因此您需要自己指定layoutX和layoutY(+节点尺寸),如:

node.setLayoutX(12);
node.setLayoutY(222);
node.setPrefWidth(500);
node.setPrefHeight(500);

如果您使用像VBox这样的窗格来管理其节点的布局,则需要将窗格内的节点设置为不受管理,以便您应用特定的转换。你可以通过设置:

来做到这一点
node.setManaged(false) 

我不建议您使用Canvas因为处理形状会非常困难,例如,如果您需要移除某些东西,您可能需要清除所有内容并仅重绘可见形状。

嗯,我有一些时间,所以这里是一个小例子(它可能不是最佳解决方案,但你可以采取作为参考)

<强> GraphTest

import java.util.ArrayList;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class GraphTest extends Application {

    private double orgSceneX, orgSceneY;
    private double orgTranslateX, orgTranslateY;

    private Group root = new Group();

    @Override
    public void start(Stage primaryStage) throws Exception {

        GraphNode node1 = createNode("A", 100, 100, Color.RED);
        GraphNode node2 = createNode("B", 300, 200, Color.GREEN);
        GraphNode node3 = createNode("C", 80, 300, Color.PURPLE);

        connectNodes(node1, node2, "C1");

        connectNodes(node3, node1, "C2");
        connectNodes(node3, node2, "C3");

        root.getChildren().addAll(node1, node2, node3);

        primaryStage.setScene(new Scene(root, 400, 400));

        primaryStage.show();

    }

    private void connectNodes(GraphNode node1, GraphNode node2, String edgeText) {

        Line edgeLine = new Line(node1.getCenterX(), node1.getCenterY(), node2.getCenterX(), node2.getCenterY());
        Label edgeLabel = new Label(edgeText);

        node1.addNeighbor(node2);
        node2.addNeighbor(node1);

        node1.addEdge(edgeLine, edgeLabel);
        node2.addEdge(edgeLine, edgeLabel);

        root.getChildren().addAll(edgeLine, edgeLabel);

    }

    private GraphNode createNode(String nodeName, double xPos, double yPos, Color color) {
        GraphNode node = new GraphNode(nodeName, xPos, yPos, color);
        node.setOnMousePressed(circleOnMousePressedEventHandler);
        node.setOnMouseDragged(circleOnMouseDraggedEventHandler);

        return node;
    }

    EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent t) {
            orgSceneX = t.getSceneX();
            orgSceneY = t.getSceneY();

            GraphNode node = (GraphNode) t.getSource();

            orgTranslateX = node.getTranslateX();
            orgTranslateY = node.getTranslateY();
        }
    };

    EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = new EventHandler<MouseEvent>() {

        @Override
        public void handle(MouseEvent t) {
            double offsetX = t.getSceneX() - orgSceneX;
            double offsetY = t.getSceneY() - orgSceneY;
            double newTranslateX = orgTranslateX + offsetX;
            double newTranslateY = orgTranslateY + offsetY;

            GraphNode node = (GraphNode) t.getSource();

            node.setTranslateX(newTranslateX);
            node.setTranslateY(newTranslateY);

            updateLocations(node);
        }
    };

    private void updateLocations(GraphNode node) {

        ArrayList<GraphNode> connectedNodes = node.getConnectedNodes();

        ArrayList<Line> edgesList = node.getEdges();

        for (int i = 0; i < connectedNodes.size(); i++) {

            GraphNode neighbor = connectedNodes.get(i);
            Line l = edgesList.get(i);

            l.setStartX(node.getCenterX());

            l.setStartY(node.getCenterY());

            l.setEndX(neighbor.getCenterX());

            l.setEndY(neighbor.getCenterY());
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

}

<强> GraphNode

import java.util.ArrayList;
import javafx.beans.binding.DoubleBinding;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;

public class GraphNode extends StackPane {

    private Circle circle;
    private Label text;

    private ArrayList<GraphNode> connectedNodesList = new ArrayList<>();
    private ArrayList<Line> edgesList = new ArrayList<>();
    private ArrayList<Label> edgesLabelList = new ArrayList<>();

    private double radius = 50.0;

    public GraphNode(String name, double xPos, double yPos, Color color) {

        circle = new Circle(radius, color);
        text = new Label(name);
        text.setTextFill(Color.WHITE);

        setLayoutX(xPos);
        setLayoutY(yPos);

        getChildren().addAll(circle, text);
        layout();
    }

    public void addNeighbor(GraphNode node) {
        connectedNodesList.add(node);
    }

    public void addEdge(Line edgeLine, Label edgeLabel) {
        edgesList.add(edgeLine);
        edgesLabelList.add(edgeLabel);

        // If user move the node we should translate the edge labels as well
        // one way of doing that is by make a custom binding to the layoutXProperty as well
        // as to layoutYProperty. We will listen for changes to the currentNode translate properties
        // and for changes of our neighbor.


        edgeLabel.layoutXProperty().bind(new DoubleBinding() {
            {
                bind(translateXProperty());
                bind(connectedNodesList.get(connectedNodesList.size() - 1).translateXProperty());
            }

            @Override
            protected double computeValue() {

                // We find the center of the line to translate the text
                double width = edgeLine.getEndX() - edgeLine.getStartX();

                return edgeLine.getStartX() + width / 2.0;
            }
        });

        edgeLabel.layoutYProperty().bind(new DoubleBinding() {
            {
                bind(translateYProperty());
                bind(connectedNodesList.get(connectedNodesList.size() - 1).translateYProperty());
            }

            @Override
            protected double computeValue() {

                double width = edgeLine.getEndY() - edgeLine.getStartY();
                return edgeLine.getStartY() + width / 2.0;
            }
        });

    }

    public ArrayList<GraphNode> getConnectedNodes() {
        return connectedNodesList;
    }

    public ArrayList<Line> getEdges() {
        return edgesList;
    }

    public double getX() {
        return getLayoutX() + getTranslateX();
    }

    public double getY() {
        return getLayoutY() + getTranslateY();
    }

    public double getCenterX() {
        return getX() + radius;
    }

    public double getCenterY() {
        return getY() + radius;
    }

}

输出看起来像那样:

Graph

您可以使用鼠标移动节点,您将看到所有标签将遵循形状位置(Cicle,Lines)