简体   繁体   English

JavaFX 在 fxml 中调整画布大小

[英]JavaFX resize canvas in fxml

I'm trying to resize a canvas in Javafx.我正在尝试在 Javafx 中调整画布的大小。 I am using scene builder and fxml.我正在使用场景构建器和 fxml。 So far, when the user clicks on the canvas the canvas turns black, and when I resize the screen and click on the canvas only the original size of the canvas turns black (canvas is not being resized).到目前为止,当用户单击画布时,画布变黑,当我调整屏幕大小并单击画布时,只有画布的原始大小变黑(画布未调整大小)。 I'm not sure how to solve this.我不知道如何解决这个问题。 Any ideas or solutions would help alot.任何想法或解决方案都会有很大帮助。

Code:代码:

Controller:控制器:

public class MainFXMLController implements Initializable
{

    @FXML
    private Canvas mainCanvas;

    @FXML

    public GraphicsContext gc;

    public void initGraphics()
    {
        gc = mainCanvas.getGraphicsContext2D();
    }

    public void drawClicked(MouseEvent me)
    {

        gc.clearRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight());
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight());
        System.out.println("Current mosue position: " + me.getX() + ":" + me.getY());
    }

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {
        initGraphics();

    }  
}

Fxml:文件格式:

<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="750.0"  xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"  fx:controller="app.MainFXMLController">
 <children>
    <Canvas fx:id="mainCanvas" height="565.0" onMouseClicked="#drawClicked" width="750.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="35.0" />

Main Java file:主Java文件:

public class DrawFx extends Application
{

    @Override
    public void start(Stage stage) throws Exception
    {
        Parent root = FXMLLoader.load(getClass().getResource("MainFXML.fxml"));

        Scene scene = new Scene(root);
        stage.setTitle("DrawFx");
        stage.getIcons().add(new Image("/icon/icon.png"));
        stage.setScene(scene);
        stage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}

First some Javadocs :)首先是一些 Javadocs :)

A Canvas node is constructed with a width and height that specifies the size of the image into which the canvas drawing commands are rendered. Canvas 节点是用宽度和高度构造的,该宽度和高度指定了在其中呈现画布绘图命令的图像的大小。 All drawing operations are clipped to the bounds of that image.所有绘图操作都被裁剪到该图像的边界。

So every time the user resize the window we need to change the width of the canvas and then we need to re-draw the canvas.所以每次用户调整窗口大小时,我们都需要改变画布的宽度,然后我们需要重新绘制画布。

Lets start by adding a fx:id to the root layout.让我们首先添加一个fx:id到根布局。

<AnchorPane fx:id="anchorPane" prefHeight="600.0" prefWidth="750.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.MainFXMLController">
    <children>
        <Canvas fx:id="mainCanvas" height="565.0" onMouseClicked="#drawClicked" width="750.0"   AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="35.0"/>
    </children>
</AnchorPane>

Next step is to add a change listener to the root layout which will set the new height and width to the canvas and then redraw it.下一步是向根布局添加一个更改侦听器,它将为画布设置新的高度和宽度,然后重新绘制它。 We can do it inside the initialize() of the controller.我们可以在控制器的initialize()中完成。

public class Controller implements Initializable {

    @FXML
    AnchorPane anchorPane;

    @FXML
    private Canvas mainCanvas;

    @FXML
    public GraphicsContext gc;

    public void initGraphics() {
        gc = mainCanvas.getGraphicsContext2D();
    }

    public void drawClicked() {
        gc.clearRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight());
        gc.setFill(Color.BLACK);
        gc.fillRect(0, 0, mainCanvas.getWidth(), mainCanvas.getHeight());
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        initGraphics();

        anchorPane.prefWidthProperty().addListener((ov, oldValue, newValue) -> {
            mainCanvas.setWidth(newValue.doubleValue());
            drawClicked();
        });

        anchorPane.prefHeightProperty().addListener((ov, oldValue, newValue) -> {
            mainCanvas.setHeight(newValue.doubleValue());
            drawClicked();
        });
    }
}

I haven't created a new method for reDraw() since your drawClicked() wasn't doing anything.我还没有为reDraw()创建一个新方法,因为你的drawClicked()没有做任何事情。 But, you can separate both the methods once it makes more sense.但是,一旦更有意义,您就可以将这两种方法分开。

The last thing is to bind to root layout's prefWidthProperty() and prefHeightProperty() to the scene's width and height respectively.最后一件事是将根布局的prefWidthProperty()prefHeightProperty()分别绑定到场景的宽度和高度。

public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) throws IOException {
        AnchorPane root = FXMLLoader.load(getClass().getResource("MainFXML.fxml"));

        Scene scene = new Scene(root);

        stage.setTitle("DrawFx");
        stage.setScene(scene);
        stage.show();

        root.prefWidthProperty().bind(scene.widthProperty());
        root.prefHeightProperty().bind(scene.heightProperty());
    }
}

If you want to resize canvas in fxml and presumably redraw its contents afterwards, the absolute minimum set is something like this:如果你想在 fxml 中调整画布的大小并可能在之后重绘其内容,绝对最小集是这样的:

test.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="test.TestController">
  <children>
    <Pane fx:id="pane" VBox.vgrow="ALWAYS">
      <children>
        <Canvas fx:id="canvas" height="${pane.height}" width="${pane.width}"
                onWidthChange="#redraw" onHeightChange="#redraw" />
      </children>
    </Pane>
  </children>
</VBox>

TestController.java

package test;

import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;

public class TestController {
  @FXML
  private Canvas canvas;

  @FXML
  private void redraw() {
    double w=canvas.getWidth();
    double h=canvas.getHeight();
    GraphicsContext gc=canvas.getGraphicsContext2D();
    gc.clearRect(0, 0, w, h);
    gc.beginPath();
    gc.rect(10, 10, w-20, h-20);
    gc.stroke();
  }
}


Wrapping (it is not part of the functionality, just provided for completeness) 包装(它不是功能的一部分,只是为了完整性而提供)

Test.java

 package test; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; public class Test extends Application { @Override public void start(Stage primaryStage) throws Exception { FXMLLoader loader=new FXMLLoader(getClass().getResource("test.fxml")); Parent root=loader.load(); primaryStage.setTitle("Test"); primaryStage.setScene(new Scene(root)); primaryStage.show(); } public static void main(String[] args) { launch(args); } }

the test package is there for allowing modular magic, test包用于允许模块化魔术,

module-info.java

 module cnvtest { requires transitive javafx.graphics; requires javafx.fxml; opens test to javafx.fxml; exports test; }

and there are really no more files.并且真的没有更多文件了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM