How to make resizable canvas in javaFX?

In javaFX there is no such method for resizing the canvas for this, the only solution is to expand from Canvas.

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); } @Override public boolean isResizable() { return true; } } 

extends from Canvas - the only solution to make canvas resizable? because this solution only works if we do not want to use FXML, if we declare a canvas in fxml, how can we make it mutable?

this is my code:

 package sample; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { Controller controller; @Override public void start(Stage primaryStage) throws Exception{ FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml")); AnchorPane root = loader.load(); // controller initialized controller = loader.getController(); GraphicsContext gc = controller.canvas.getGraphicsContext2D(); gc.setFill(Color.AQUA); gc.fillRect(0, 0, root.getPrefWidth(), root.getPrefHeight()); primaryStage.setTitle("Hello World"); primaryStage.setScene(new Scene(controller.Pane, controller.Pane.getPrefWidth(), controller.Pane.getPrefHeight())); primaryStage.show(); } public static void main(String[] args) { launch(args); } } 
+11
javafx javafx-2 canvas javafx-8 fxml
source share
5 answers

Here's a guide that I think might be useful for setting up resizable canvas:

JavaFx tip - resizable canvas

A piece of code from the manual:

 /** * 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(); } } 
+5
source share

Adapted from http://werner.yellowcouch.org/log/resizable-javafx-canvas/ : To resize a JavaFx canvas, all you need to do is override the min / pref / max methods. Make it resizable and implement the resize method .

With this method, width and height listeners are not needed to trigger a redraw. There is also no need to associate the width and height with the container.

 public class ResizableCanvas extends Canvas { @Override public double minHeight(double width) { return 64; } @Override public double maxHeight(double width) { return 1000; } @Override public double prefHeight(double width) { return minHeight(width); } @Override public double minWidth(double height) { return 0; } @Override public double maxWidth(double height) { return 10000; } @Override public boolean isResizable() { return true; } @Override public void resize(double width, double height) { super.setWidth(width); super.setHeight(height); <paint> } 
+4
source share

I found that the solutions above do not work when the canvas is contained in HBox, since HBox will not decrease when the window is resized, as it will crop the canvas. Thus, the HBox will expand, but will never become smaller. I used the following code so that the canvas matches the container:

 public class ResizableCanvas extends Canvas { @Override public double prefWidth(double height) { return 0; } @Override public double prefHeight(double width) { return 0; } } 

And in my controller class:

 @FXML private HBox canvasContainer; private Canvas canvas = new ResizableCanvas(); ... @Override public void start(Stage primaryStage) throws Exception { ... canvas.widthProperty().bind(canvasContainer.widthProperty()); canvas.heightProperty().bind(canvasContainer. pane.getChildren().add(canvas); ... } 
+2
source share

Of all the methods shown, this was the only method that really allowed you to resize the canvas:

 public class ResizableCanvas extends Canvas { @Override public boolean isResizable() { return true; } @Override public double maxHeight(double width) { return Double.POSITIVE_INFINITY; } @Override public double maxWidth(double height) { return Double.POSITIVE_INFINITY; } @Override public double minWidth(double height) { return 1D; } @Override public double minHeight(double width) { return 1D; } @Override public void resize(double width, double height) { this.setWidth(width); this.setHeight(height) } } 

I did not want to break encapsulation by forcing the parent component to send us width and height ; I also did not want to make the canvas the only child in it, occupying all the space; and finally, a canvas was drawn in another class, so the drawing method did not live inside the canvas.

With this canvas, I don’t need to bind its parent width / height properties to resize the canvas. It simply resizes with any size selected by the parent. In addition, anyone using a canvas can simply bind its width / height properties and control their own drawing when these properties change.

+2
source share

The canvas class just needs to override isResizable () (everything else that is suggested in other examples is actually optional):

 public class ResizableCanvas extends Canvas { public boolean isResizable() { return true; } } 

And in the application, the properties of the width and height of the canvas should be tied to the parent canvas element:

 @Override public void start(Stage primaryStage) throws Exception { ... StackPane pane = new StackPane(); ResizableCanvas canvas = new ResizableCanvas(width, height); canvas.widthProperty().bind(pane.widthProperty()); canvas.heightProperty().bind(pane.heightProperty()); pane.getChildren().add(_canvas); ... } 

Listeners can be added to the width width properties to redraw the canvas when it is resized (but if you need it and where to place it, it depends on your application):

 widthProperty().addListener(this::paint); heightProperty().addListener(this::paint); 
+1
source share

All Articles