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.setStroke(Color.RED);
			gc.strokeLine(0, 0, width, height);
			gc.strokeLine(0, height, width, 0);
		}

		@Override
		public boolean isResizable() {
			return true;
		}

		@Override
		public double prefWidth(double height) {
			return getWidth();
		}

		@Override
		public double prefHeight(double width) {
			return getHeight();
		}
	}

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

		StackPane stackPane = new StackPane();
		stackPane.getChildren().add(canvas);

		// Bind canvas size to stack pane size.
		canvas.widthProperty().bind(
                       stackPane.widthProperty());
		canvas.heightProperty().bind(
                       stackPane.heightProperty());

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

	public static void main(String[] args) {
		launch(args);
	}
}

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