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); } }
[…] posts this week, both of which are tips for fellow JavaFX developers. Firstly, he has posted about creating a resizable canvas in JavaFX, and secondly he has posted a tip about how to ensure lines are sharp / non-blurry when […]
[…] posts this week, both of which are tips for fellow JavaFX developers. Firstly, he has posted about creating a resizable canvas in JavaFX, and secondly he has posted a tip about how to ensure lines are sharp / non-blurry when […]
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.
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.
Reblogged this on Dinesh Ram Kali..