y32M-71693993
y32M-71693993

Reputation: 28

How to embed JavaFX Canvas into BorderPane?

I'm trying to make a application using JavaFX.

What I want to make is the window with MenuBar on the top of it and Canvas in the center. I also want the window to be able to resize. Referring to the following link, which shows how to make Canvas resizable, I first made the following code:

JavaFX Tip 1: Resizable Canvas – DLSC

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class CanvasInBorderPane extends Application {

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane borderPane = new BorderPane();

        // Put menu bar on the top of the window
        MenuBar menuBar = new MenuBar(new Menu("File"), new Menu("Edit"),
                new Menu("Help"));
        borderPane.setTop(menuBar);

        // Put canvas in the center of the window (*)
        Canvas canvas = new Canvas();
        borderPane.setCenter(canvas);
        // Bind the width/height property so that the size of the Canvas will be
        // resized as the window is resized
        canvas.widthProperty().bind(borderPane.widthProperty());
        canvas.heightProperty().bind(borderPane.heightProperty());
        // redraw when resized
        canvas.widthProperty().addListener(event -> draw(canvas));
        canvas.heightProperty().addListener(event -> draw(canvas));
        draw(canvas);

        Scene scene = new Scene(borderPane);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * Draw crossed red lines which each each end is at the corner of window,
     * and 4 blue circles whose each center is at the corner of the window,
     * so that make it possible to know where is the extent the Canvas draws
     */
    private void draw(Canvas canvas) {
        int width = (int) canvas.getWidth();
        int height = (int) canvas.getHeight();
        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.clearRect(0, 0, width, height);
        gc.setStroke(Color.RED);
        gc.strokeLine(0, 0, width, height);
        gc.strokeLine(0, height, width, 0);
        gc.setFill(Color.BLUE);
        gc.fillOval(-30, -30, 60, 60);
        gc.fillOval(-30 + width, -30, 60, 60);
        gc.fillOval(-30, -30 + height, 60, 60);
        gc.fillOval(-30 + width, -30 + height, 60, 60);
    }
}

Then I got a window like (1) (See the picture below.)

I know this is because the actual size the Canvas should be is smaller than the size of borderPane. But I don't know how to get the CENTER region of the BorderPane.

I then tried putting a wrapper Pane in the center of the borderPane and embed the Canvas into it, binding the width and height of the wrapper Pane to the Canvas. I changed the 10+ lines of the code above which initializes the Canvas (which start from the comment-line with (*)) as follows:

        // Create a wrapper Pane first
        BorderPane wrapperPane = new BorderPane();
        borderPane.setCenter(wrapperPane);
        // Put canvas in the center of the window
        Canvas canvas = new Canvas();
        wrapperPane.setCenter(canvas);
        // Bind the width/height property to the wrapper Pane
        canvas.widthProperty().bind(wrapperPane.widthProperty());
        canvas.heightProperty().bind(wrapperPane.heightProperty());
        // redraw when resized
        canvas.widthProperty().addListener(event -> draw(canvas));
        canvas.heightProperty().addListener(event -> draw(canvas));
        draw(canvas);

Then something strange happened. When I increased the width of the window, everything went good as I supposed. (Picture (2))

However, though I decreased the width, the width of the Canvas wouldn't decrease, in other words, fit to the size of the window. (Picture (3))

And so does the height.

Does anybody have an idea to do away with this problem? My Java version is 1.8.0_71.

The screenshots of the window

Upvotes: 1

Views: 6029

Answers (1)

James_D
James_D

Reputation: 209339

Use a plain Pane to wrap the canvas, instead of a BorderPane:

    // Create a wrapper Pane first
    Pane wrapperPane = new Pane();
    borderPane.setCenter(wrapperPane);
    // Put canvas in the center of the window
    Canvas canvas = new Canvas();
    wrapperPane.getChildren().add(canvas);
    // Bind the width/height property to the wrapper Pane
    canvas.widthProperty().bind(wrapperPane.widthProperty());
    canvas.heightProperty().bind(wrapperPane.heightProperty());
    // redraw when resized
    canvas.widthProperty().addListener(event -> draw(canvas));
    canvas.heightProperty().addListener(event -> draw(canvas));
    draw(canvas);

Upvotes: 3

Related Questions