import javafx.application.Application; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.geometry.Point2D; import javafx.scene.Scene; import javafx.scene.canvas.*; import javafx.scene.canvas.Canvas; import javafx.scene.control.*; import javafx.scene.input.*; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.FileChooser; import javafx.stage.Stage; import java.io.*; public class GraphEditorApp extends Application { public static int WIDTH = 500; public static int HEIGHT = 250; private Graph graph; // The model (i.e. the graph) private Node dragNode; // The Node being dragged private Point2D elasticEndLocation; private Edge dragEdge; // The Edge being dragged private Point2D dragPoint; // The starting point that the Edge was selected at private GraphicsContext aPen; public Graph getGraph() { return graph; } public void setGraph(Graph g) { graph = g; update(); } public void start(Stage primaryStage) { graph = Graph.example(); VBox p = new VBox(); // Create the File menu Menu fileMenu = new Menu("_File"); MenuItem loadItem = new MenuItem("Load"); loadItem.setAccelerator(KeyCombination.keyCombination("Ctrl+L")); MenuItem saveItem = new MenuItem("Save"); saveItem.setAccelerator(KeyCombination.keyCombination("Ctrl+S")); fileMenu.getItems().addAll(loadItem, saveItem); // Set up the event handlers for the File menu loadItem.setOnAction(new EventHandler() { public void handle(ActionEvent e) { FileChooser chooser = new FileChooser(); chooser.setInitialDirectory(new File("C:\\")); chooser.setTitle("Load Graph"); File f = chooser.showOpenDialog(primaryStage); if (f != null) { try { BufferedReader file = new BufferedReader(new FileReader(f.getAbsolutePath())); graph = Graph.loadFrom(file); file.close(); update(); } catch (Exception ex) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("Error !"); alert.setHeaderText(null); alert.setContentText("Error Loading Graph From File !"); alert.showAndWait(); } } } }); saveItem.setOnAction(new EventHandler() { public void handle(ActionEvent e) { FileChooser chooser = new FileChooser(); chooser.setInitialDirectory(new File("C:\\")); chooser.setTitle("Save Graph"); File f = chooser.showSaveDialog(primaryStage); if (f != null) { try { PrintWriter file = new PrintWriter(new FileWriter(f.getAbsolutePath())); graph.saveTo(file); file.close(); } catch (Exception ex) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("Error !"); alert.setHeaderText(null); alert.setContentText("Error Saving Graph To File !"); alert.showAndWait(); } } } }); // Add the menus to a menubar and then add the menubar to the pane MenuBar menuBar = new MenuBar(); menuBar.getMenus().add(fileMenu); p.getChildren().add(menuBar); Canvas canvas = new Canvas(WIDTH, HEIGHT); p.getChildren().add(canvas); Scene scene = new Scene(p, WIDTH, HEIGHT+25); // Display the graph onto the canvas aPen = canvas.getGraphicsContext2D(); graph.draw(aPen); primaryStage.setTitle("Graph Editor"); primaryStage.setScene(scene); primaryStage.show(); // Handle a mouse-press in the canvas canvas.setOnMousePressed(new EventHandler() { public void handle(MouseEvent ev) { Node aNode = graph.nodeAt(ev.getX(), ev.getY()); if (ev.getClickCount() == 2) { if (aNode == null) { // We missed a node, now try for an edge midpoint Edge anEdge = graph.edgeAt(ev.getX(), ev.getY()); if (anEdge == null) graph.addNode(new Node(ev.getX(), ev.getY())); else anEdge.toggleSelected(); } else aNode.toggleSelected(); // Update the view, by redrawing the Graph update(); } else { if (aNode != null) { dragNode = aNode; // If we pressed on a node, store it dragEdge = null; } else dragEdge = graph.edgeAt(ev.getX(), ev.getY()); dragPoint = new Point2D(ev.getX(), ev.getY()); } } }); // Handle a mouse-release in the canvas canvas.setOnMouseReleased(new EventHandler() { public void handle(MouseEvent ev) { Node aNode = graph.nodeAt(ev.getX(), ev.getY()); // Check to see if we have let go on a node if ((dragNode != null) && (aNode != null) && (aNode != dragNode)) // Change the model, by adding a new Edge graph.addEdge(dragNode, aNode); // Update the view, by redrawing the Graph dragNode = null; // No need to remember this anymore update(); } }); // Handle a mouse-drag in the canvas canvas.setOnMouseDragged(new EventHandler() { public void handle(MouseEvent ev) { elasticEndLocation = new Point2D(ev.getX(), ev.getY()); if (dragNode != null) { if (dragNode.isSelected()) { for (Node n: graph.selectedNodes()) { n.setLocation(n.getLocation().getX() + ev.getX() - dragPoint.getX(), n.getLocation().getY() + ev.getY() - dragPoint.getY()); } dragPoint = new Point2D(ev.getX(), ev.getY()); } } if (dragEdge != null) { if (dragEdge.isSelected()) { dragEdge.getStartNode().setLocation( dragEdge.getStartNode().getLocation().getX() + ev.getX() - dragPoint.getX(), dragEdge.getStartNode().getLocation().getY() + ev.getY() - dragPoint.getY()); dragEdge.getEndNode().setLocation( dragEdge.getEndNode().getLocation().getX() + ev.getX() - dragPoint.getX(), dragEdge.getEndNode().getLocation().getY() + ev.getY() - dragPoint.getY()); dragPoint = new Point2D(ev.getX(), ev.getY()); } } update(); // We have changed the model, so now update } }); canvas.requestFocus(); // Needed to handle key events canvas.setOnKeyReleased(new EventHandler() { public void handle(KeyEvent ev) { if (ev.getCode() == KeyCode.DELETE) { // Delete all selected Edges for (Edge e: graph.selectedEdges()) graph.deleteEdge(e); // Delete all selected Nodes for (Node n: graph.selectedNodes()) graph.deleteNode(n); // Update the view, by redrawing the Graph update(); } } }); } // Update the view by redrawing the graph onto the Canvas private void update() { aPen.setFill(Color.WHITE); aPen.fillRect(0, 0, WIDTH, HEIGHT); graph.draw(aPen); // Draw the elastic band if (dragNode != null) if (!dragNode.isSelected()) aPen.strokeLine(dragNode.getLocation().getX(), dragNode.getLocation().getY(), elasticEndLocation.getX(), elasticEndLocation.getY()); } public static void main(String[] args) { launch(args); } }