繁体   English   中英

使用 FXML 加载器访问 JavaFX 场景中的 Canvas

[英]Accessing a Canvas in JavaFX scene using FXML Loader

所以我试图制作一个包含 canvas 的窗格的场景。 这个 canvas 需要在这个窗格内,因为我将在它旁边显示信息。 我使用scenebuilder创建了一个窗格,然后在其中放置了一个名为“绘图”的画布。 然后我加载场景并尝试在 canvas 中绘制,但是我得到并错误地说 canvas 是 null。 我知道有类似问题的答案,但是在我不觉得的情况下,他们没有回答我的问题。 如果他们这样做,您能否解释一下,因为我不明白。

package uk.ac.rhul.cs3821;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.stage.Stage;

public class TurtleView extends Application {

  private static volatile TurtleView instance = null;
  
  Turtle turtle = new Turtle(0,0,0);
  
  @FXML
  private Canvas drawing;
  
  private GraphicsContext gc;
  
  @FXML
  void initialize() {
    instance = this;
  }

  /**
   * Creates a JavaFX instance and Launches the JavaFX application.
   * 
   * @return the JavaFX instance running
   */
  public static synchronized TurtleView getInstance() {
    if (instance == null) {
      new Thread(() -> Application.launch(TurtleView.class)).start();
      // Wait until the instance is ready since initialise has executed.
      while (instance == null) {// empty body
      }
    }

    return instance;
  }
  
  @Override
  public void start(Stage primaryStage) throws Exception {
    Parent root = FXMLLoader.load(RuleView.class.getResource("TurtleView.fxml"));
    Scene scene = new Scene(root, 800, 500);
    primaryStage.setScene(scene);
    primaryStage.show();
    gc = drawing.getGraphicsContext2D();
  }
    

}

你应该解决的问题

  1. JavaFX 应用程序 class 负责实现应用程序生命周期

    • 对于一个 class 来说,这是很多责任。

    • 你不应该要求它做更多的事情。

    • 在小型演示应用程序中,应用程序 class 通常会做所有事情,但这只是因为它们是小型演示程序,除此之外,不同类的功能分开。

  2. 从来没有应用程序 class 也充当 controller。

    • 当您查看前面的应用程序生命周期定义时,您可以看到 VM 中应该只有一个应用程序实例,该实例是在调用 launch() 时创建的,并且只能调用一次。

    • 默认情况下,FXML 加载器将在 FXML 中定义的fx:controller class 上创建一个实例。 如果 class 是一个应用程序,那么 controller 将创建另一个应用程序实例,但它不会知道启动的实例,这将非常令人困惑,因为某些字段将在一个实例中初始化,而某些字段将在另一个实例中初始化。

  3. getInstance() 方法很奇怪。

    • 我不确定它的用途以及您为什么拥有它。

    • 不管是什么原因,可能有更好的方法来处理它。

    • 我不会在这里讨论更多,但您可能想针对实例管理提出一个具有特定mcve的新问题,该问题解释了您在做什么以及为什么,并询问一种更好的方法来实现您的明确目标.

  4. 因为应用程序不是 controller 它不应该包含:

    • a controller initialize() 方法(main()、 init()start()方法是应用程序初始化的钩子)。

    • 没有@FXML注释字段,因为这些字段应该只存在于 controller 中。

那你该怎么办?

请参阅此答案中的示例 hello 应用程序:

只需忽略答案中所有无关紧要的 exe 打包内容,然后查看代码结构、文件布局、构建工具使用等方面的所有其他内容,然后按照这些内容进行操作(这将是“文件树”和“文件”部分的答案)。 它演示了如何使用 FXML 构建一个简单的 hello world 应用程序。

链接示例 hello world JavaFX 应用程序最初由Idea New JavaFX 项目向导创建。 如果你有想法,你可以运行它来创建一个新项目,然后为你的实现修改它,否则你可以将链接答案中的代码复制到 IDE 中的一个新项目中并修改它。

主观设计意见

几个额外的设计点,它们不是那么重要,如果你愿意,你可以忽略。 设计是主观的,有不同的实施策略都可以。 您更了解您的应用程序,因此请选择最适合您的应用程序。

  • 您的应用程序可以有多个 FXML 文件,并非所有节点都需要在 FXML 中定义,您可以混合使用两种不同的节点创建系统。

  • Perhaps have a class (non-FXML) which creates a canvas and responds to events and drawing commands on the canvas, and a separate class (an FXML controller) for managing the UI controls that interfaces with the drawing class.

  • class 中唯一的 @FXML 注释字段是 canvas。

    • 如果 class 仅包含单个节点实例,则在不使用 FXML 的代码中创建节点会更容易。

    • 只有当您有一个包含大量节点的更复杂的布局时,FXML 才真正有用。

    • 这是主观的,您仍然可以拥有一个只有一个 @FXML 字段的 controller,并且以这种方式实现就可以了。

暂无
暂无

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

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