2017-10-04 69 views
-1

我正在用javaFX制作应用程序。该应用程序由用户创建一种“图形”。 用户通过一个按钮创建一个节点(由具有JAVAFX图形的圆圈创建)并将其关联到一个变量,重复该过程,创建另一个节点,等等。现在我需要弄清楚如何在特定的保留空间内定义节点位置。显然,在创建节点后,通过另一个按钮,用户创建与节点关联的弧(由连接两个节点的线创建),从而定义一个图。 我的问题是,我不明白如何指示将在我的图中作为弧线的线的位置。使用javafx定义运行时的对象位置

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

+1

请更新您的问题给小(可运行)例如什么你已经完成了。 – JKostikiadis

回答

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); 

否则,如果你在一个布局窗格内工作,你需要知道组件是否管理。例如,一个窗格或AnchorPane节点的自动布局被禁用里面,所以你需要自己指定其layoutX和layoutY(+节点的尺寸),如:

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

如果您使用的是像垂直框中,窗格,其管理您需要将窗格中的节点设置为非托管,以便您应用特定的转换,从而为其节点布局。你可以这样做,只是通过设置:

node.setManaged(false) 

,我不会建议你用帆布引起操作形状会很辛苦,例如,如果您需要删除你可能要清除一切,只有重绘的东西可见的形状。

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

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,线)

+0

这是一个真实的例子,我用SCENE BUILDER做了所有的事情,但不幸的是我用可见和不可见的节点/弧来“玩”。 从某种意义上说,我绘制了5个节点和所有可能的链接,然后只使用户需要的节点和弧可见。当然,这种策略并不好,我需要弄清楚如何将它们放置在该布局中(而不是画布)。图片被分类。 1)https://ibb.co/kFLeOw 2)https://ibb.co/fcbawG 3)https://ibb.co/kuVeOw 4)https://ibb.co/kKB8GG 5) https://ibb.co/eeVeOw 6)https:// ibb。7)https://ibb.co/gHzjqb – Applefriend

+0

所以你使用的布局,在这种情况下,你需要将所有的节点设置为.setManaged(false),然后以编程方式,你可以通过调用设置他们的位置setLayoutX&setLayoutY。当然,我会建议通过拖放实现移动看看这里:http://java-buddy.blogspot.gr/2013/07/javafx-drag-and-move-something.html – JKostikiadis

+0

我希望我可以做这样,但对于两个节点之间的弧线,我该怎么做呢? – Applefriend

相关问题