簡體   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