【问题标题】:Accessing a Canvas in JavaFX scene using FXML Loader使用 FXML Loader 在 JavaFX 场景中访问 Canvas
【发布时间】:2021-12-12 06:29:10
【问题描述】:

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

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();
  }
    

}

【问题讨论】:

    标签: java javafx canvas


    【解决方案1】:

    您应该解决的问题

    1. JavaFX 应用程序类负责实现application lifecycle

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

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

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

    2. 永远不要让应用程序类同时充当控制器。

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

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

    3. getInstance() 方法很奇怪。

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

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

      • 我不会在这里谈论更多,但您可能想问一个带有特定 mcve 的新问题,仅针对实例管理,解释您在做什么以及为什么并询问更好的实现方法你解释清楚的目标。

    4. 因为应用程序不是控制器,所以它不应该包含:

      • 控制器 initialize() 方法(main()、init()start() 方法是应用程序初始化的挂钩)。

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

    那你该怎么办?

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

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

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

    主观设计方法

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

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

    • 可能有一个类(非 FXML)创建画布并响应画布上的事件和绘图命令,以及一个单独的类(FXML 控制器)用于管理与绘图类接口的 UI 控件。

    • 类中唯一的@FXML 注释字段是画布。

      • 如果一个类只包含一个节点实例,那么在不使用 FXML 的代码中创建节点会更容易。

      • FXML 仅在您拥有包含大量节点的更复杂布局时才真正有用。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      • 2016-07-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-09
      相关资源
      最近更新 更多