Drawing and animation

IA tooling, not an exam topic. These are JavaFX patterns for drawing tools, simulations, and small games. Most form-and-table IAs will not need them. Nothing here is examinable, and your IA must be your own work.

A Canvas is a blank rectangle you draw on directly with shapes, lines, text, and images. This page covers drawing on it, reacting to the mouse, and running a smooth animation loop. Reach for these only if your IA is a drawing tool, a simulation, or a game-style app.

New here? Read Start here: how every recipe fits together first; it explains the two places you edit and the fx:id link every recipe relies on.


Draw shapes and lines on a canvas

What this does: draws shapes, lines, and text onto a Canvas using its GraphicsContext, the object that holds the drawing commands.

When you would use it in your IA: a board for a game, a simple diagram, a chart you want full control over, or any free-form drawing surface.

In SceneBuilder (the layout): add a Canvas, give it an fx:id of canvas, and set its width and height.

<Canvas fx:id="canvas" width="300" height="200" />

In the controller (the .java file):

Imports:

import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

Controller:

@FXML private Canvas canvas;

@FXML
public void initialize() {
    GraphicsContext gc = canvas.getGraphicsContext2D();

    // your IA logic here: what to draw
    gc.setFill(Color.CORNFLOWERBLUE);
    gc.fillRect(20, 20, 100, 60);          // x, y, width, height

    gc.setStroke(Color.DARKRED);
    gc.strokeLine(20, 100, 200, 100);      // from (x1, y1) to (x2, y2)

    gc.fillOval(140, 20, 50, 50);          // x, y, width, height of the bounding box

    gc.strokeText("Hello", 20, 150);       // text at (x, y)
}

Where your own logic goes: the drawing calls marked // your IA logic here, which are your picture. Getting the GraphicsContext is reusable wiring.

Make it your own:

  • Change the colours, coordinates, and sizes for your own drawing.
  • setFill then a fill... method draws a solid shape; setStroke then a stroke... method draws an outline.

Watch out for:

  • The fx:id canvas must match the @FXML field name exactly, or the screen will not load.
  • Coordinates start at (0, 0) in the top-left corner, and y increases downward, not upward. This trips up most people once.
  • A canvas is “paint and forget”: you are drawing pixels, not objects. Once a shape is drawn it has no identity, so to move or remove it you clear the area and draw again. The animation recipe below relies on this.

Mix with: Draw where the user clicks or drags, Run a smooth animation or game loop.


Draw where the user clicks or drags

What this does: reads the mouse position on the canvas and draws there, so the user can click or drag to make marks.

When you would use it in your IA: a paint or sketch tool, placing pieces on a board, or letting the user mark points on a diagram.

In SceneBuilder (the layout): add the Canvas (fx:id canvas) and set both onMousePressed and onMouseDragged to the same handler, handleDraw.

<Canvas fx:id="canvas" width="300" height="200"
        onMousePressed="#handleDraw" onMouseDragged="#handleDraw" />

In the controller (the .java file):

Imports:

import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;

Controller (one handler covers both a click and a drag):

@FXML private Canvas canvas;

@FXML
private void handleDraw(MouseEvent event) {
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.setFill(Color.BLACK);
    // your IA logic here: what to draw at the mouse position
    // event.getX() and event.getY() are the mouse position on the canvas.
    gc.fillOval(event.getX() - 5, event.getY() - 5, 10, 10);
}

Where your own logic goes: what you draw at the mouse position, marked // your IA logic here. Reading the mouse position from the event is reusable wiring.

Make it your own:

  • Change what you draw at the mouse position: a dot, a line from the last point, a game piece.
  • onMousePressed fires once per click; onMouseDragged fires repeatedly as the mouse moves with the button down. Using both gives a continuous brush.
  • Subtracting 5 (half the 10-wide oval) centres the mark on the cursor.

Watch out for:

  • The fx:id canvas must match the @FXML field name, and handleDraw must exist in the controller with a MouseEvent parameter, or the screen will not load.
  • event.getX() and event.getY() are measured from the canvas’s top-left corner, which is what you want when drawing on it.
  • For a separate “released” action (for example finishing a line), add onMouseReleased pointing at another method.

Mix with: Draw shapes and lines on a canvas, React to the Enter key.


Run a smooth animation or game loop

What this does: runs a piece of code on every frame (about 60 times a second) using an AnimationTimer, which is what gives smooth motion.

When you would use it in your IA: moving a sprite, a physics or particle simulation, or any game loop that updates and redraws continuously.

In SceneBuilder (the layout): add the Canvas (fx:id canvas) you draw on. The loop is created in code.

<Canvas fx:id="canvas" width="300" height="200" />

In the controller (the .java file):

Imports:

import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

Controller:

@FXML private Canvas canvas;

private double ballX = 0;

@FXML
public void initialize() {
    GraphicsContext gc = canvas.getGraphicsContext2D();

    AnimationTimer loop = new AnimationTimer() {
        @Override
        public void handle(long now) {
            // 1. wipe the canvas so the last frame does not leave a trail
            gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());

            // your IA logic here: update positions and draw this frame
            gc.setFill(Color.TOMATO);
            gc.fillOval(ballX, 80, 30, 30);

            ballX += 2;
            if (ballX > canvas.getWidth()) {
                ballX = 0;                         // wrap back to the left
            }
        }
    };
    loop.start();
}

Where your own logic goes: the per-frame update and drawing, marked // your IA logic here. The loop, the clear, and the start/stop are reusable wiring.

Make it your own:

  • Put your own per-frame logic in handle: move things, check collisions, redraw.
  • Keep the moving values (positions, speeds) as fields so they carry over between frames.
  • Call loop.stop() to pause the animation, and loop.start() to resume.

Watch out for:

  • The fx:id canvas must match the @FXML field name exactly, or the screen will not load.
  • Clear the canvas at the start of each frame, or every drawing stays and you get smears instead of motion.
  • handle runs around 60 times a second, so keep the work inside it light. Heavy work there makes the whole app stutter.
  • AnimationTimer is the heavier cousin of Timeline. Use Timeline for a fixed beat like a one-second countdown, and AnimationTimer when you need smooth, every-frame motion.
  • The new AnimationTimer() { ... } form is an anonymous class with an overridden handle method. The override is ordinary OOP; the inline class is a convenience for giving the timer its one method.

Mix with: Do something on a repeating beat, Keep the UI responsive during slow work, Play a sound.


© EduCS.me — A resource hub for Computer Science education

This site uses Just the Docs, a documentation theme for Jekyll.