{"id":"drawing-and-images-mouse","slug":"mouse","title":"Drawing with the mouse","text":"A canvas can react to the mouse, as a button reacts to clicks. That turns it into something to draw on.\n\n### Mouse events\n\nA node has four methods for the mouse, each taking an event handler, usually a lambda as in module 49:\n\n| method | its handler runs when |\n| --- | --- |\n| `setOnMousePressed` | a mouse button goes down on the node |\n| `setOnMouseDragged` | the mouse moves while its button is down |\n| `setOnMouseReleased` | the button comes up again |\n| `setOnMouseClicked` | the button went down and came up on the node: a click |\n\nThe handler gets a **MouseEvent** (from `javafx.scene.input`), and `event.getX()` and `event.getY()` say where the mouse was, in the canvas's own coordinates: (0, 0) is the canvas's top left corner, wherever the canvas is in the window. Both are doubles. A test pad that prints every event:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.layout.Pane;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 120);\n        canvas.setOnMousePressed(event -> System.out.println(\"pressed at (\" + event.getX() + \", \" + event.getY() + \")\"));\n        canvas.setOnMouseDragged(event -> System.out.println(\"dragged to (\" + event.getX() + \", \" + event.getY() + \")\"));\n        canvas.setOnMouseReleased(event -> System.out.println(\"released at (\" + event.getX() + \", \" + event.getY() + \")\"));\n        canvas.setOnMouseClicked(event -> System.out.println(\"clicked at (\" + event.getX() + \", \" + event.getY() + \")\"));\n\n        stage.setScene(new Scene(new Pane(canvas)));\n        stage.setTitle(\"Test pad\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[\"click Canvas 1 at 40 30\",\"press Canvas 1 at 100 60\",\"drag Canvas 1 to 120 70\",\"drag Canvas 1 to 140 80\",\"release Canvas 1 at 140 80\"],\"window\":{\"windows\":[{\"title\":\"Test pad\",\"scene\":{\"root\":{\"n\":1,\"type\":\"Pane\",\"children\":[{\"n\":2,\"type\":\"Canvas\",\"width\":200,\"height\":120,\"onMousePressed\":true,\"onMouseDragged\":true,\"onMouseReleased\":true,\"onMouseClicked\":true,\"calls\":[]}]}}}],\"problems\":[]},\"outline\":\"Window \\\"Test pad\\\"\\n  Pane\\n    Canvas 200 x 120\"}\n```\n\n```output\npressed at (40.0, 30.0)\nreleased at (40.0, 30.0)\nclicked at (40.0, 30.0)\npressed at (100.0, 60.0)\ndragged to (120.0, 70.0)\ndragged to (140.0, 80.0)\nreleased at (140.0, 80.0)\nclicked at (140.0, 80.0)\n```\n\nThe event lines work like part 13's clicks and typing, with a point added. `click Canvas 1 at 40 30` clicks the first canvas of the window at (40, 30). `press`, `drag ... to` and `release` move the mouse one step at a time: here it's pressed at (100, 60), moved with its button down to (120, 70) and then (140, 80), and let go there.\n\n- A click is three events, in this order: pressed, released, clicked.\n- A drag runs the dragged handler once for each point the mouse moves to. On a real screen that's every few pixels, so a handler for drags runs often.\n- After the drag, JavaFX still counts a **click**: the button went down and came up on the same node. A program that draws on clicks and on drags must keep that in mind.\n\n### Drawing where the mouse is\n\nA game's level editor plants a flower in a meadow at each click: a gold circle 16 pixels across with its center at the mouse, and a small brown center in it. `start` draws the grass first:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 120);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        pen.setFill(Color.YELLOWGREEN);\n        pen.fillRect(0, 0, 200, 120);\n        canvas.setOnMouseClicked(event -> {\n            double x = event.getX();\n            double y = event.getY();\n            pen.setFill(Color.GOLD);\n            pen.fillOval(x - 8, y - 8, 16, 16);\n            pen.setFill(Color.SADDLEBROWN);\n            pen.fillOval(x - 3, y - 3, 6, 6);\n        });\n\n        stage.setScene(new Scene(new Pane(canvas)));\n        stage.setTitle(\"Meadow\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[\"click Canvas 1 at 40 30\",\"click Canvas 1 at 100 80\",\"click Canvas 1 at 160 45\"],\"window\":{\"windows\":[{\"title\":\"Meadow\",\"scene\":{\"root\":{\"n\":1,\"type\":\"Pane\",\"children\":[{\"n\":2,\"type\":\"Canvas\",\"width\":200,\"height\":120,\"onMouseClicked\":true,\"calls\":[{\"op\":\"fillRect\",\"args\":[0,0,200,120],\"fill\":\"#9acd32\"},{\"op\":\"fillOval\",\"args\":[32,22,16,16],\"fill\":\"#ffd700\"},{\"op\":\"fillOval\",\"args\":[37,27,6,6],\"fill\":\"#8b4513\"},{\"op\":\"fillOval\",\"args\":[92,72,16,16],\"fill\":\"#ffd700\"},{\"op\":\"fillOval\",\"args\":[97,77,6,6],\"fill\":\"#8b4513\"},{\"op\":\"fillOval\",\"args\":[152,37,16,16],\"fill\":\"#ffd700\"},{\"op\":\"fillOval\",\"args\":[157,42,6,6],\"fill\":\"#8b4513\"}]}]}}}],\"problems\":[]},\"outline\":\"Window \\\"Meadow\\\"\\n  Pane\\n    Canvas 200 x 120\\n      fillRect 0 0 200 120, fill #9acd32\\n      fillOval 32 22 16 16, fill #ffd700\\n      fillOval 37 27 6 6, fill #8b4513\\n      fillOval 92 72 16 16, fill #ffd700\\n      fillOval 97 77 6 6, fill #8b4513\\n      fillOval 152 37 16 16, fill #ffd700\\n      fillOval 157 42 6 6, fill #8b4513\"}\n```\n\nThe handler draws on the same `pen` that `start` used: a canvas keeps everything drawn on it, so each flower is added to the grass and the flowers before it. To center a circle 16 across on the mouse, its square starts 8 pixels to the left of the mouse and 8 above it. In the window as text, the grass's call comes first, then two calls for each click, in the order of the clicks.\n\n### Lines that follow the mouse\n\nTo draw a line as the mouse moves, the program joins each point to the one before it with a short line. So it has to remember the last point, from one event to the next. The handlers are lambdas, which can't change a local variable of `start` (module 49), so the point goes in two instance variables. A doodle pad, with buttons for the color and one to wipe it clean:\n\n```java\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.control.Button;\nimport javafx.scene.layout.HBox;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    private double lastX;\n    private double lastY;\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(240, 140);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        pen.setLineWidth(3);\n        canvas.setOnMousePressed(event -> {\n            this.lastX = event.getX();\n            this.lastY = event.getY();\n        });\n        canvas.setOnMouseDragged(event -> {\n            pen.strokeLine(this.lastX, this.lastY, event.getX(), event.getY());\n            this.lastX = event.getX();\n            this.lastY = event.getY();\n        });\n\n        Button black = new Button(\"Black\");\n        black.setOnAction(event -> pen.setStroke(Color.BLACK));\n        Button red = new Button(\"Red\");\n        red.setOnAction(event -> pen.setStroke(Color.RED));\n        Button clear = new Button(\"Clear\");\n        clear.setOnAction(event -> pen.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()));\n\n        stage.setScene(new Scene(new VBox(new HBox(5, black, red, clear), canvas)));\n        stage.setTitle(\"Doodle pad\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n```\n\n```window\n{\"events\":[\"press Canvas 1 at 20 100\",\"drag Canvas 1 to 60 40\",\"drag Canvas 1 to 100 100\",\"release Canvas 1 at 100 100\",\"click Button \\\"Red\\\"\",\"press Canvas 1 at 140 70\",\"drag Canvas 1 to 180 40\",\"drag Canvas 1 to 220 70\",\"release Canvas 1 at 220 70\"],\"window\":{\"windows\":[{\"title\":\"Doodle pad\",\"scene\":{\"root\":{\"n\":1,\"type\":\"VBox\",\"children\":[{\"n\":2,\"type\":\"HBox\",\"spacing\":5,\"children\":[{\"n\":3,\"type\":\"Button\",\"text\":\"Black\",\"onAction\":true},{\"n\":4,\"type\":\"Button\",\"text\":\"Red\",\"onAction\":true},{\"n\":5,\"type\":\"Button\",\"text\":\"Clear\",\"onAction\":true}]},{\"n\":6,\"type\":\"Canvas\",\"width\":240,\"height\":140,\"onMousePressed\":true,\"onMouseDragged\":true,\"calls\":[{\"op\":\"strokeLine\",\"args\":[20,100,60,40],\"stroke\":\"#000000\",\"lineWidth\":3},{\"op\":\"strokeLine\",\"args\":[60,40,100,100],\"stroke\":\"#000000\",\"lineWidth\":3},{\"op\":\"strokeLine\",\"args\":[140,70,180,40],\"stroke\":\"#ff0000\",\"lineWidth\":3},{\"op\":\"strokeLine\",\"args\":[180,40,220,70],\"stroke\":\"#ff0000\",\"lineWidth\":3}]}]}}}],\"problems\":[]},\"outline\":\"Window \\\"Doodle pad\\\"\\n  VBox\\n    HBox spacing 5\\n      Button \\\"Black\\\"\\n      Button \\\"Red\\\"\\n      Button \\\"Clear\\\"\\n    Canvas 240 x 140\\n      strokeLine 20 100 60 40, stroke #000000, width 3\\n      strokeLine 60 40 100 100, stroke #000000, width 3\\n      strokeLine 140 70 180 40, stroke #ff0000, width 3\\n      strokeLine 180 40 220 70, stroke #ff0000, width 3\"}\n```\n\n- Pressing only remembers where the line starts. Each drag draws from the remembered point to the new one, and then remembers the new one, so the short lines join up.\n- The color buttons just call `pen.setStroke(...)`. The GraphicsContext keeps its stroke color, so every line drawn after a click on Red is red, until another button changes it.\n- `clearRect(x, y, width, height)` wipes a rectangle clean: the canvas there is empty again, as at the start (the window shows through). With the canvas's own size, it wipes everything. In the window as text, a wiped canvas still lists what was drawn before it, followed by the `clearRect` line: the list is the canvas's whole history, in order.\n\n### Drawing yourself\n\nThe windows drawn in a lesson show the events listed with them, and can't be clicked. When you run a challenge's code with \"Run with my input\", or a program in the Playground, you can use its window: on a canvas that has mouse handlers, draw with the mouse or a finger. The page collects the whole movement (the press, a drag every few pixels and the release) and runs your program once with all of it, so the drawing updates when you lift your finger. A tap without moving is a click. With the keyboard, the arrow keys move a point, Enter clicks there, and Space presses there and, after the arrow keys have moved the point, lets go.\n","task":"A park ranger marks on a map where birds have built their nests. The starter code makes a canvas of 200 x 150 pixels with the label `Nests: 0` under it. Make each click on the canvas mark a nest: an orange (`Color.ORANGE`) filled circle 12 pixels across, with its center where the mouse was clicked. The label then says how many nests are marked: `Nests: 2` after two clicks. The window after the two clicks listed below is drawn under them.\n","kind":"code","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 150);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        Label nests = new Label(\"Nests: 0\");\n\n        stage.setScene(new Scene(new VBox(canvas, nests)));\n        stage.setTitle(\"Nest map\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    private int marked;\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 150);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        Label nests = new Label(\"Nests: 0\");\n        pen.setFill(Color.ORANGE);\n        canvas.setOnMouseClicked(event -> {\n            pen.fillOval(event.getX() - 6, event.getY() - 6, 12, 12);\n            this.marked++;\n            nests.setText(\"Nests: \" + this.marked);\n        });\n\n        stage.setScene(new Scene(new VBox(canvas, nests)));\n        stage.setTitle(\"Nest map\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["`canvas.setOnMouseClicked(event -> { ... });` runs at each click. The circle's square starts 6 pixels left of and above the mouse: `pen.fillOval(event.getX() - 6, event.getY() - 6, 12, 12);`.","The count has to survive from one click to the next, so keep it in an instance variable, `private int marked;`, and add one to it in the handler before setting the label's text."],"tests":[{"name":"Test 1","stdin":"","expect":"","hidden":false,"events":["click Canvas 1 at 50 40","click Canvas 1 at 120 95"],"window":{"windows":[{"title":"Nest map","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Canvas","width":200,"height":150,"onMouseClicked":true,"calls":[{"op":"fillOval","args":[44,34,12,12],"fill":"#ffa500"},{"op":"fillOval","args":[114,89,12,12],"fill":"#ffa500"}]},{"n":3,"type":"Label","text":"Nests: 2"}]}}}],"problems":[]},"outline":"Window \"Nest map\"\n  VBox\n    Canvas 200 x 150\n      fillOval 44 34 12 12, fill #ffa500\n      fillOval 114 89 12 12, fill #ffa500\n    Label \"Nests: 2\""},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":["click Canvas 1 at 10 10","click Canvas 1 at 190 140","click Canvas 1 at 100 75"],"window":{"windows":[{"title":"Nest map","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Canvas","width":200,"height":150,"onMouseClicked":true,"calls":[{"op":"fillOval","args":[4,4,12,12],"fill":"#ffa500"},{"op":"fillOval","args":[184,134,12,12],"fill":"#ffa500"},{"op":"fillOval","args":[94,69,12,12],"fill":"#ffa500"}]},{"n":3,"type":"Label","text":"Nests: 3"}]}}}],"problems":[]},"outline":"Window \"Nest map\"\n  VBox\n    Canvas 200 x 150\n      fillOval 4 4 12 12, fill #ffa500\n      fillOval 184 134 12 12, fill #ffa500\n      fillOval 94 69 12 12, fill #ffa500\n    Label \"Nests: 3\""},{"name":"Test 3","stdin":"","expect":"","hidden":true,"events":["click Canvas 1 at 33.5 61"],"window":{"windows":[{"title":"Nest map","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Canvas","width":200,"height":150,"onMouseClicked":true,"calls":[{"op":"fillOval","args":[27.5,55,12,12],"fill":"#ffa500"}]},{"n":3,"type":"Label","text":"Nests: 1"}]}}}],"problems":[]},"outline":"Window \"Nest map\"\n  VBox\n    Canvas 200 x 150\n      fillOval 27.5 55 12 12, fill #ffa500\n    Label \"Nests: 1\""}],"require":[],"forbid":[],"more":[{"task":"A delivery app asks for a signature. Under the label `Sign below`, in a VBox with no spacing, a canvas of 240 x 100 pixels takes it: pressing the mouse starts a line, and each drag draws a line from the point before to the new point, in dark blue (`Color.DARKBLUE`) and 2 pixels wide. Releasing draws nothing. Nothing else is drawn. The window after the events below is drawn under them.\n","kind":"code","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(240, 100);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n\n        stage.setScene(new Scene(new VBox(new Label(\"Sign below\"), canvas)));\n        stage.setTitle(\"Sign here\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.control.Label;\nimport javafx.scene.layout.VBox;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    private double lastX;\n    private double lastY;\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(240, 100);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        pen.setStroke(Color.DARKBLUE);\n        pen.setLineWidth(2);\n        canvas.setOnMousePressed(event -> {\n            this.lastX = event.getX();\n            this.lastY = event.getY();\n        });\n        canvas.setOnMouseDragged(event -> {\n            pen.strokeLine(this.lastX, this.lastY, event.getX(), event.getY());\n            this.lastX = event.getX();\n            this.lastY = event.getY();\n        });\n\n        stage.setScene(new Scene(new VBox(new Label(\"Sign below\"), canvas)));\n        stage.setTitle(\"Sign here\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["Keep the last point in two instance variables, `private double lastX;` and `private double lastY;`. The pressed handler only stores the point.","The dragged handler draws `pen.strokeLine(this.lastX, this.lastY, event.getX(), event.getY());` and then stores the new point. Set the stroke color and the width once, in `start`."],"tests":[{"name":"Test 1","stdin":"","expect":"","hidden":false,"events":["press Canvas 1 at 20 70","drag Canvas 1 to 40 30","drag Canvas 1 to 60 70","drag Canvas 1 to 80 40","release Canvas 1 at 80 40"],"window":{"windows":[{"title":"Sign here","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Label","text":"Sign below"},{"n":3,"type":"Canvas","width":240,"height":100,"onMousePressed":true,"onMouseDragged":true,"calls":[{"op":"strokeLine","args":[20,70,40,30],"stroke":"#00008b","lineWidth":2},{"op":"strokeLine","args":[40,30,60,70],"stroke":"#00008b","lineWidth":2},{"op":"strokeLine","args":[60,70,80,40],"stroke":"#00008b","lineWidth":2}]}]}}}],"problems":[]},"outline":"Window \"Sign here\"\n  VBox\n    Label \"Sign below\"\n    Canvas 240 x 100\n      strokeLine 20 70 40 30, stroke #00008b, width 2\n      strokeLine 40 30 60 70, stroke #00008b, width 2\n      strokeLine 60 70 80 40, stroke #00008b, width 2"},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":["press Canvas 1 at 100 50","drag Canvas 1 to 130 20","release Canvas 1 at 130 20","press Canvas 1 at 150 80","drag Canvas 1 to 170 60","drag Canvas 1 to 200.5 75","release Canvas 1 at 200.5 75"],"window":{"windows":[{"title":"Sign here","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Label","text":"Sign below"},{"n":3,"type":"Canvas","width":240,"height":100,"onMousePressed":true,"onMouseDragged":true,"calls":[{"op":"strokeLine","args":[100,50,130,20],"stroke":"#00008b","lineWidth":2},{"op":"strokeLine","args":[150,80,170,60],"stroke":"#00008b","lineWidth":2},{"op":"strokeLine","args":[170,60,200.5,75],"stroke":"#00008b","lineWidth":2}]}]}}}],"problems":[]},"outline":"Window \"Sign here\"\n  VBox\n    Label \"Sign below\"\n    Canvas 240 x 100\n      strokeLine 100 50 130 20, stroke #00008b, width 2\n      strokeLine 150 80 170 60, stroke #00008b, width 2\n      strokeLine 170 60 200.5 75, stroke #00008b, width 2"},{"name":"Test 3","stdin":"","expect":"","hidden":true,"events":["click Canvas 1 at 120 50"],"window":{"windows":[{"title":"Sign here","scene":{"root":{"n":1,"type":"VBox","children":[{"n":2,"type":"Label","text":"Sign below"},{"n":3,"type":"Canvas","width":240,"height":100,"onMousePressed":true,"onMouseDragged":true,"calls":[]}]}}}],"problems":[]},"outline":"Window \"Sign here\"\n  VBox\n    Label \"Sign below\"\n    Canvas 240 x 100"}],"require":[],"forbid":[]},{"task":"A room planner draws furniture as rectangles. Drag on the canvas from one corner of a piece to the opposite corner: where the mouse is pressed is one corner, and where it's released is the other. On release, draw the rectangle between them: first filled in light steel blue (`Color.LIGHTSTEELBLUE`), then its outline with the same numbers in the pen's own stroke (black, 1 pixel wide). Its top left corner is at the smaller x and the smaller y of the two points, and its width and height are the distances between them, so a drag up or to the left works too. When the width or the height is 0 (a click, say), draw nothing. Nothing is drawn while the mouse moves. The window after the events below is drawn under them.\n","kind":"code","seed":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 150);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n\n        stage.setScene(new Scene(new Pane(canvas)));\n        stage.setTitle(\"Room planner\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","solution":"import javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.canvas.Canvas;\nimport javafx.scene.canvas.GraphicsContext;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    private double startX;\n    private double startY;\n\n    @Override\n    public void start(Stage stage) {\n        Canvas canvas = new Canvas(200, 150);\n        GraphicsContext pen = canvas.getGraphicsContext2D();\n        pen.setFill(Color.LIGHTSTEELBLUE);\n        canvas.setOnMousePressed(event -> {\n            this.startX = event.getX();\n            this.startY = event.getY();\n        });\n        canvas.setOnMouseReleased(event -> {\n            double x = Math.min(this.startX, event.getX());\n            double y = Math.min(this.startY, event.getY());\n            double width = Math.abs(event.getX() - this.startX);\n            double height = Math.abs(event.getY() - this.startY);\n            if (width > 0 && height > 0) {\n                pen.fillRect(x, y, width, height);\n                pen.strokeRect(x, y, width, height);\n            }\n        });\n\n        stage.setScene(new Scene(new Pane(canvas)));\n        stage.setTitle(\"Room planner\");\n        stage.show();\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n","hints":["The pressed handler stores the first corner in two instance variables. The released handler has the other corner in `event.getX()` and `event.getY()`.","`Math.min(this.startX, event.getX())` is the left edge, and `Math.abs(event.getX() - this.startX)` the width; the same for y. Then `fillRect` and `strokeRect` with those four numbers, inside an `if` that checks both are above 0."],"tests":[{"name":"Test 1","stdin":"","expect":"","hidden":false,"events":["press Canvas 1 at 20 30","drag Canvas 1 to 60 50","release Canvas 1 at 80 70","press Canvas 1 at 180 130","release Canvas 1 at 120 90"],"window":{"windows":[{"title":"Room planner","scene":{"root":{"n":1,"type":"Pane","children":[{"n":2,"type":"Canvas","width":200,"height":150,"onMousePressed":true,"onMouseReleased":true,"calls":[{"op":"fillRect","args":[20,30,60,40],"fill":"#b0c4de"},{"op":"strokeRect","args":[20,30,60,40],"stroke":"#000000","lineWidth":1},{"op":"fillRect","args":[120,90,60,40],"fill":"#b0c4de"},{"op":"strokeRect","args":[120,90,60,40],"stroke":"#000000","lineWidth":1}]}]}}}],"problems":[]},"outline":"Window \"Room planner\"\n  Pane\n    Canvas 200 x 150\n      fillRect 20 30 60 40, fill #b0c4de\n      strokeRect 20 30 60 40, stroke #000000, width 1\n      fillRect 120 90 60 40, fill #b0c4de\n      strokeRect 120 90 60 40, stroke #000000, width 1"},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":["press Canvas 1 at 150 120","release Canvas 1 at 110 60","click Canvas 1 at 30 30","press Canvas 1 at 10 10","release Canvas 1 at 70 10","press Canvas 1 at 10 100","drag Canvas 1 to 90 100","release Canvas 1 at 90 140.5"],"window":{"windows":[{"title":"Room planner","scene":{"root":{"n":1,"type":"Pane","children":[{"n":2,"type":"Canvas","width":200,"height":150,"onMousePressed":true,"onMouseReleased":true,"calls":[{"op":"fillRect","args":[110,60,40,60],"fill":"#b0c4de"},{"op":"strokeRect","args":[110,60,40,60],"stroke":"#000000","lineWidth":1},{"op":"fillRect","args":[10,100,80,40.5],"fill":"#b0c4de"},{"op":"strokeRect","args":[10,100,80,40.5],"stroke":"#000000","lineWidth":1}]}]}}}],"problems":[]},"outline":"Window \"Room planner\"\n  Pane\n    Canvas 200 x 150\n      fillRect 110 60 40 60, fill #b0c4de\n      strokeRect 110 60 40 60, stroke #000000, width 1\n      fillRect 10 100 80 40.5, fill #b0c4de\n      strokeRect 10 100 80 40.5, stroke #000000, width 1"}],"require":[],"forbid":[]}]}