2017-10-04 1 views
-1

Ich mache eine Anwendung mit javaFX. Die Anwendung besteht darin, vom Benutzer eine Art "Graph" zu erstellen. Der Benutzer erstellt über einen Button einen Knoten (wird durch einen Kreis mit JAVAFX-Figur erstellt) und verknüpft ihn mit einer Variablen, wiederholt den Prozess, erstellt einen weiteren Knoten und so weiter. Jetzt muss ich herausfinden, wie man die Knotenposition in einem speziell reservierten Bereich definiert. Offensichtlich erstellt der Benutzer nach dem Erstellen von Knoten durch eine andere Schaltfläche die Bögen (die durch eine Linie entstehen, die zwei Knoten verbindet), die den Knoten zugeordnet sind, und definiert so ein Diagramm. Mein Problem ist, dass ich nicht verstehe, wie man die Position von Linien angibt, die in meinem Graphen als Bögen fungieren.Definieren Sie die Objektposition zur Laufzeit mit javafx

Bitte helfen Sie mir.Ich bin nicht sehr erfahren und ich versuche, dieses Problem anzugehen.

+1

Bitte aktualisieren Sie Ihre Frage ein kleines (runnable) Beispiel zu geben, was du hast es schon getan. – JKostikiadis

Antwort

0

Zuerst müssen Sie uns sagen, was ist Ihr "reservierter Platz"? Wenn es sich um ein Canvas handelt, können Sie Formen mit Canvas GraphicsContext zeichnen.

Andernfalls, wenn Sie in einem Bereich mit Layout arbeiten, müssen Sie wissen, ob die Komponenten verwaltet werden oder nicht. Zum Beispiel in einem Fenster oder AnchorPane des Knotens automatisches Layout deaktiviert ist, so müssen Sie ihre layoutX und layoutY selbst spezifizieren (+ Knoten Abmessungen) wie:

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

Wenn Sie eine Scheibe wie VBox verwenden, die die Verwaltung Layout seiner Knoten müssen Sie festlegen, dass die Knoten innerhalb des Bereichs nicht verwaltet werden, damit Sie bestimmte Transformationen anwenden können. Sie können das tun nur, indem:

node.setManaged(false) 

ich nicht empfehlen Sie Leinwand zu verwenden, verursachen die Formen der Handhabung sehr schwierig sein wird, zum Beispiel, wenn Sie etwas entfernen müssen, müssen Sie wahrscheinlich alles löschen und neu zu zeichnen nur die sichtbare Formen.

Nun, ich hatte so hier einige Zeit ist ein kleines Beispiel (Es ist vielleicht nicht die optimale Lösung sein, aber Sie können nehmen als Referenz)

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

} 

Und der Ausgang würde so aussehen:

Graph

Sie können die Knoten mit der Maus bewegen und Sie werden sehen, dass alle Etiketten, die die Formen Standorte folgen (Ciclo, Linien)

+0

Dies ist ein echtes Beispiel, ich habe alles mit SCENE BUILDER gemacht, aber leider habe ich mit sichtbaren und unsichtbaren Knoten/Bögen "gespielt". In dem Sinne, dass ich 5 Knoten und alle möglichen Links gezeichnet habe, und dann nur die Knoten und Bögen sichtbar gemacht, die vom Benutzer benötigt werden. Natürlich ist diese Strategie nicht gut und ich muss herausfinden, wie man sie innerhalb dieses Layouts positioniert (keine Leinwand). Die Bilder sind sortiert. 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.co/nu6awG 7) https://ibb.co/gHzjqb – Applefriend

+0

Sie verwenden also ein Layout, in diesem Fall müssen Sie alle Knoten als .setManaged (false) setzen und dann programmgesteuert ihren Standort durch Aufruf festlegen setLayoutX & setLayoutY. Natürlich würde ich vorschlagen, Bewegung per Drag & Drop zu implementieren, schaue hier nach: http://java-buddy.blogspot.gr/2013/07/javafx-drag-and-move-something.html – JKostikiadis

+0

Ich hoffe ich kann es tun es auf diese Weise, aber für die Bögen zwischen zwei Knoten, wie kann ich es tun? – Applefriend

Verwandte Themen