JavaFX Tip 1: Resizable Canvas

While working on FlexGanttFX I had to deal a lot with the JavaFX Canvas node. I am using it to render activities on a timeline. Each row in the Gantt chart is a Canvas node. The user has the option to resize each row individually. So I had to figure out the best way to resize a canvas, which out-of-the-box is not resizable. The listing below shows how this can be accomplished.

The main steps needed are:

  • Create a subclass of Canvas.
  • Override the isResizable() method and return true.
  • Override the prefWidth() and prefHeight() methods. Return the values of Canvas.getWidth() and Canvas.getHeight().
  • Add listeners to the width and height properties of Canvas in order to trigger a redraw when the size of the canvas changes.
  • Bind the width and height properties of Canvas to the width and height properties of the parent pane.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

 * Tip 1: A canvas resizing itself to the size of
 *        the parent pane.
public class Tip1ResizableCanvas extends Application {

	class ResizableCanvas extends Canvas {

		public ResizableCanvas() {
			// Redraw canvas when size changes.
			widthProperty().addListener(evt -> draw());
			heightProperty().addListener(evt -> draw());

		private void draw() {
			double width = getWidth();
			double height = getHeight();

			GraphicsContext gc = getGraphicsContext2D();
			gc.clearRect(0, 0, width, height);

			gc.strokeLine(0, 0, width, height);
			gc.strokeLine(0, height, width, 0);

		public boolean isResizable() {
			return true;

		public double prefWidth(double height) {
			return getWidth();

		public double prefHeight(double width) {
			return getHeight();

	public void start(Stage stage) throws Exception {
		ResizableCanvas canvas = new ResizableCanvas();

		StackPane stackPane = new StackPane();

		// Bind canvas size to stack pane size.

		stage.setScene(new Scene(stackPane));
		stage.setTitle("Tip 1: Resizable Canvas");;

	public static void main(String[] args) {

When run you should see the following:
Bildschirmfoto 2014-04-10 um 11.30.31


  1. Nice blog! I wasn’t really aware of the isResizable method – recently I overrode StackPane.layoutChildren() to manually resize a child canvas, and I didn’t quite stop to think about why I had to do that.

  2. If you do it that way then I think you will notice a little bit of a delay before the canvas content (the rendering / drawing) is actually updated.

  3. The parameters of prefHeight() and prefWidth() are not reversed. The input for the calculation of the preferred height is the width of the control and vice versa.

  4. If you use next scene graph all works properly

    |_ StackPane
    |_ Canvas

    But if Canvas placed in any Node which itself placed in another Node and so on, then this solution does not work!

    |_ StackPane mainPane
    |_ StackPane canvasContainer
    |_ Canvas

    Canvas will grow, but never decreases. This problem is more actual, when you have many other controls in your scene graph.

    Any other solutions?

  5. it only work,when stage.setScene(new Scene(stackPane)); if wrap stackPane with BorderPane, only when stage is becoming bigger, but not becoming smaller

  6. public class CanvasPane extends Pane{

    private ResizableCanvas canvas;

    public CanvasPane(ResizableCanvas canvas){
    this.canvas = canvas;

    protected void layoutChildren() {
    final int top = (int)snappedTopInset();
    final int right = (int)snappedRightInset();
    final int bottom = (int)snappedBottomInset();
    final int left = (int)snappedLeftInset();
    final int w = (int)getWidth() – left – right;
    final int h = (int)getHeight() – top – bottom;
    if (w != canvas.getWidth() || h != canvas.getHeight()) {

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s