2017-10-04 41 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

相關問題