Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make canvas Resizable in javaFX?

In javaFX to resize a canvas there is no such method to do that, the only solution is to extends 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;
    }
}

is extends from Canvas is the only solution to make canvas Resizable ? because this solution work only if we don't want to use FXML, if we declare in fxml a canvas how can we make it resizable?

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);
    }
}
like image 338
HinoHara Avatar asked Jul 02 '14 14:07

HinoHara


2 Answers

There's a guide that I think that you may find useful for setting up a resizable canvas:

JavaFx tip - resizable canvas

Piece of code from the guide:

/**
 * 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();
        }
    }
like image 159
Maslor Avatar answered Sep 30 '22 19:09

Maslor


Of all the answers given, none of them actually worked for me in terms of making the canvas automatically resize with its parent. I decided to take a crack at this and this is what I came up with:

import javafx.scene.canvas.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);
    }
}

This was the only one that actually made the canvas truly resizable.


My reasons for going with this approach is as follows:

  • I didn't want to break encapsulation by forcing the parent component to send us a width and height in the constructor which would also mean that the canvas cannot be used in FXML.
  • I also did not want to depend on the parent's width and height properties thus making the canvas the only child in it's parent, by taking up all the space.
  • Finally, the canvas needed to have it's drawing done in another class, which meant I could not use the current accepted answer which also included drawing to canvas via a draw method.

With this canvas, I do not need to bind to its parent width/height properties to make the canvas resize. It just resizes with whatever size the parent chooses. In addition, anyone using the canvas can just bind to its width/height properties and manage their own drawing when these properties change.

like image 27
smac89 Avatar answered Sep 30 '22 19:09

smac89