JavaFX FXML画布绘制后为空。

3

我使用Intellij IDEA进行JavaFX FXML开发。我使用下面的代码简单绘制一个矩形,但它从未显示出来。

Main.java

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 600, 400));
        primaryStage.show();
    }


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

Controller.java

public class Controller implements Initializable {
public Mat image;
@FXML public Canvas img = new Canvas(300,300);
public GraphicsContext gc = img.getGraphicsContext2D();
@FXML private void drawCanvas(ActionEvent event) {
    gc.setFill(Color.AQUA);
    gc.fillRect(10,10,100,100);
}
@Override
public void initialize(URL location, ResourceBundle resources) {
        gc.setFill(Color.BLACK);
        System.out.println("color set to black");
        gc.fillRect(50, 50, 100, 100);
        System.out.println("draw rectangle");
    }
}

我在Button OnAction和initialize方法中都使用了setFill()和fillRect(),但仍然无法绘制矩形。
sample.fxml

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
   <top>
      <ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
        <items>
          <Button mnemonicParsing="false" onAction="#drawCanvas" text="draw" />
        </items>
      </ToolBar>
   </top>
   <bottom>
      <AnchorPane prefHeight="41.0" prefWidth="600.0" BorderPane.alignment="CENTER">
         <children>
            <Label fx:id="co" layoutX="14.0" layoutY="9.0" text="co" />
            <Label fx:id="rgb" layoutX="144.0" layoutY="13.0" text="RGB" />
            <Label fx:id="zoom" layoutX="245.0" layoutY="9.0" text="zoom" />
         </children>
      </AnchorPane>
   </bottom>
   <center>
      <ScrollPane fx:id="img_pane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
         <content>
            <Canvas fx:id="img" height="286.0" width="355.0" />
         </content>
      </ScrollPane>
   </center>
</BorderPane>

1个回答

5

这个论坛上有很多类似的问题,但我无法通过快速搜索找到它们。

永远不要初始化一个被标记为@FXML的字段。 @FXML的整个意义在于该字段在加载FXML文件的过程中被初始化。

因此,在您的类初始化程序中,您创建了一个Canvas,然后将gc分配给其图形上下文:

@FXML public Canvas img = new Canvas(300,300);
public GraphicsContext gc = img.getGraphicsContext2D();

然后,当你加载FXML文件时,FXMLLoader根据FXML的描述创建一个新的Canvas,将该新Canvas分配给字段img,并将新的Canvas放置在场景图中(然后在舞台中显示)。但是,gc仍然是原始Canvas的图形上下文,而你从未显示它。因此,对gc进行的任何图形操作都将无法实现。

你需要:

public class Controller implements Initializable {

    @FXML private Canvas img ;

    private GraphicsContext gc ;

    @FXML private void drawCanvas(ActionEvent event) {
        gc.setFill(Color.AQUA);
        gc.fillRect(10,10,100,100);
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        gc = img.getGraphicsContext2D();
        gc.setFill(Color.BLACK);
        System.out.println("color set to black");
        gc.fillRect(50, 50, 100, 100);
        System.out.println("draw rectangle");
    }

}

哇!感谢您提供如此详细的教程。我自学了JavaFX FXML,但是真的没有太多的教程。所以所有标记为 @FXML 的内容都不应该在初始化时赋值,而是应该在 initialize 方法中赋值,对吗? - Michael Liao
如果一个字段有@FXML注释,请不要初始化它。假定一切设置正确,FXMLLoader将为您初始化它。@FXML注释字段的初始化保证在调用initialize()方法之前发生。FXMLLoader的文档极其不足... - James_D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接