简体   繁体   English

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

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

So I am trying to make a scene that is a pane containing a canvas.所以我试图制作一个包含 canvas 的窗格的场景。 This canvas will need to be inside this pane as I am going to display information along side it.这个 canvas 需要在这个窗格内,因为我将在它旁边显示信息。 I have used scenebuilder to create a pane then placed a canavas called "drawing" inside of it.我使用scenebuilder创建了一个窗格,然后在其中放置了一个名为“绘图”的画布。 I then load the scene and attempt to then draw in the canvas however I get and error saying the canvas is null.然后我加载场景并尝试在 canvas 中绘制,但是我得到并错误地说 canvas 是 null。 I know there are answers to similar questions however they do not answer my question in my context I don't feel.我知道有类似问题的答案,但是在我不觉得的情况下,他们没有回答我的问题。 If they do could you please explain how as I don't understand.如果他们这样做,您能否解释一下,因为我不明白。

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

}

Issues you should address你应该解决的问题

  1. The JavaFX application class is responsible for implementing the application lifecycle . JavaFX 应用程序 class 负责实现应用程序生命周期

    • That is plenty of responsibilities for one class.对于一个 class 来说,这是很多责任。

    • You should not ask it to do more than that.你不应该要求它做更多的事情。

    • In small demo applications often the application class will do everything, but that is just because they are small demos, in anything other than that, separate functionality across different classes.在小型演示应用程序中,应用程序 class 通常会做所有事情,但这只是因为它们是小型演示程序,除此之外,不同类的功能分开。

  2. Never have an application class also act as a controller.从来没有应用程序 class 也充当 controller。

    • When you look at the application lifecycle definition from earlier, you can see that there should only be one instance of an application in a VM, which is created when launch() is invoked, which must only be invoked once.当您查看前面的应用程序生命周期定义时,您可以看到 VM 中应该只有一个应用程序实例,该实例是在调用 launch() 时创建的,并且只能调用一次。

    • By default an FXML loader will create an instance on the fx:controller class defined in the FXML.默认情况下,FXML 加载器将在 FXML 中定义的fx:controller class 上创建一个实例。 If that class is an application then the controller will create another application instance, but it will not know about the launched instance which will be very confusing to reason about as some fields will be initialized in one instance and some fields initialized in another instance.如果 class 是一个应用程序,那么 controller 将创建另一个应用程序实例,但它不会知道启动的实例,这将非常令人困惑,因为某些字段将在一个实例中初始化,而某些字段将在另一个实例中初始化。

  3. The getInstance() method is quite strange. getInstance() 方法很奇怪。

    • I am not sure what it is for and why you have it.我不确定它的用途以及您为什么拥有它。

    • Whatever the reason for it, there is probably a better way of handling it.不管是什么原因,可能有更好的方法来处理它。

    • I won't talk more about it here, but you might want to ask a new question with a specific mcve just for around the instance management that explains what you are doing and why and asks about a better approach to achieve your well-explained goal.我不会在这里讨论更多,但您可能想针对实例管理提出一个具有特定mcve的新问题,该问题解释了您在做什么以及为什么,并询问一种更好的方法来实现您的明确目标.

  4. Because an application is not a controller it should never contain:因为应用程序不是 controller 它不应该包含:

    • a controller initialize() method (the main(), init() and start() methods are hooks for application initialization). a controller initialize() 方法(main()、 init()start()方法是应用程序初始化的钩子)。

    • No @FXML annotated fields as those fields should only exist in a controller.没有@FXML注释字段,因为这些字段应该只存在于 controller 中。

So what shoud you do?那你该怎么办?

See the example hello application in this answer:请参阅此答案中的示例 hello 应用程序:

Just ignore all the exe packing stuff in the answer, that is irrelevant, and look at everything else there in terms of code structure, file layout, build tool usage, etc. and follow that (that would be the "file tree" and "files" sections of the answer).只需忽略答案中所有无关紧要的 exe 打包内容,然后查看代码结构、文件布局、构建工具使用等方面的所有其他内容,然后按照这些内容进行操作(这将是“文件树”和“文件”部分的答案)。 It demonstrates how to structure a simple hello world application using FXML.它演示了如何使用 FXML 构建一个简单的 hello world 应用程序。

The linked example hello world JavaFX application was initially created by the Idea New JavaFX Project wizard .链接示例 hello world JavaFX 应用程序最初由Idea New JavaFX 项目向导创建。 If you have idea, you can just run that to create a new project then modify it for your implementation, otherwise you can copy the code from the linked answer into a new project in your IDE and modify that.如果你有想法,你可以运行它来创建一个新项目,然后为你的实现修改它,否则你可以将链接答案中的代码复制到 IDE 中的一个新项目中并修改它。

Subjective design comments主观设计意见

A couple of additional design points, which are not that important and you can ignore if you wish.几个额外的设计点,它们不是那么重要,如果你愿意,你可以忽略。 Design is subjective and there are different implementation strategies which can all be OK.设计是主观的,有不同的实施策略都可以。 You know your app better, so choose the best one for you.您更了解您的应用程序,因此请选择最适合您的应用程序。

  • You can have multiple FXML files for your app and not all nodes need to be defined in FXML, you can mix the two different node creation systems.您的应用程序可以有多个 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. 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.

  • The only @FXML annotated field in the class is the canvas. class 中唯一的 @FXML 注释字段是 canvas。

    • If a class only contains a single node instance, it will be easier to just create the node in code not using FXML.如果 class 仅包含单个节点实例,则在不使用 FXML 的代码中创建节点会更容易。

    • FXML is only really useful when you have a more complicated layout with lots of nodes.只有当您有一个包含大量节点的更复杂的布局时,FXML 才真正有用。

    • This is subjective, you could still have a controller with just one @FXML field and it would be fine to implement that way.这是主观的,您仍然可以拥有一个只有一个 @FXML 字段的 controller,并且以这种方式实现就可以了。

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

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