JavaFX FXML ロード例外の解決策

Mehvish Ashiq 2023年10月12日
  1. JavaFX FXML ロード例外が発生する理由
  2. JavaFX FXML ロード例外の解決策
JavaFX FXML ロード例外の解決策

このチュートリアルでは、JavaFX FXML ロード例外の原因について説明し、簡単な解決策を提供します。

JavaFX FXML ロード例外が発生する理由

JavaFX FXML ロード例外が発生する最初の理由は、FXML ファイルへのパスがローダーに正しく指定されていない場合です。パス/fxml/view.fxml は、resources フォルダー、つまり classpath にある fxml という名前のフォルダー内のファイル view.fxml を参照します。

getClass().getResource() 呼び出しは、実行時にオブジェクト classloader を呼び出し、オブジェクトに渡されたリソースの classpath を検索します。このようにして、fxml フォルダと view.fxml ファイルがそのフォルダ内に見つかります。

2 番目の理由は、コンポーネント ID の不一致である可能性があります。これは、Controller ファイルのコンポーネント ID を更新したが、FXML ファイルのその ID を変更し忘れた(またはその逆)ことを意味します。この場合、Controllerview.fxml ファイルでそのコンポーネントをリンクできません。

明確に理解するには、次のチャンクを参照してください。

コントローラーファイル:

@FXML
Button btnName1

FXML ビューファイル:

fx:id="btnName_1"

以下は、これら両方の理由の解決策です。

JavaFX FXML ロード例外の解決策

このアプリケーションを実行するために、Java 18、JavaFX 13、および NetBeansIDE バージョン 13 を使用しています。選択に応じてこれらすべてを使用できます。

サンプルコード(view.fxml ファイル、ビューファイル):

<!--Step1: XML declaration-->
<?xml version="1.0" encoding="UTF-8"?>

<!--Step 2: import necessary java types in FXML-->

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<!--Step 3: specify the FXML namespace-->

<AnchorPane prefHeight="300.0" prefWidth="400.0"
xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.mycompany.javafx_fxml_loadexception.viewController">

    <!--Step 4: layout pane have children-->
    <children>
        <Button fx:id="btTest" layoutX="170.0"
        layoutY="208.0" mnemonicParsing="false"
        onAction="#onBtTestAction" text="Button" />

        <Label layoutX="167.0" layoutY="126.0" text="Cick here!" />
   </children>

</AnchorPane>

以下は、上記のコードの段階的な説明です。

  • バージョンとエンコーディングを記述して XML 宣言を記述します。
  • 必要なすべての Java タイプを FXML にインポートします。
  • AnchorPane タグを使用して、fx 名前空間プレフィックスを宣言します。このタグを使用すると、子ノードのエッジをアンカーペインのエッジからのオフセットにアンカーできます。

    アンカーペインにパディングまたは境界線がある場合、オフセットはそれらのインセットの内側のエッジから測定されます。AnchorPane タグには、簡単な説明とともに以下にリストされているさまざまなプロパティがあります。

    • prefHeight および prefWidth プロパティを使用して、領域の計算された優先の高さと幅をオーバーライドできます。
    • FXML では、fx:controller を使用して、root 要素のコントローラーを指定します。FXML ドキュメントごとに 1つのコントローラーを使用でき、root 要素で指定する必要があることに注意してください。

    このコードの root 要素は何ですか?AchnorPane タグは、このコード例の root 要素であり、FXML ドキュメントのオブジェクトグラフの最上位オブジェクトです。

    すべての UI 要素がこの要素に追加されます。さらに、コントローラーが満たさなければならないルールも知る必要があります。これらのルールを以下に示します。

    • コントローラーは、FXML ローダーによってインスタンス化されます。
    • コントローラーには、パブリック no-args コンストラクターが必要です。FXML ローダーが存在しない場合、それをインスタンス化できず、ロード時に例外が発生します。
    • コントローラーには、FXML でイベントハンドラーとして指定することもできるアクセス可能な関数を含めることができます。
    • FXML コントローラーは、コントローラーのアクセス可能なインスタンス変数を自動的に検索します。アクセス可能なインスタンス変数の名前が要素の fx:id 属性と一致する場合、FXML からのオブジェクト参照がコントローラーインスタンス変数に自動的にコピーされます。

    この機能により、FXML 内の UI 要素の参照にコントローラーがアクセスできるようになります。そうすれば、コントローラーはそれらを使用できるようになります。

    • コントローラーは initialize() 関数にアクセスすることもできます。この関数は引数を受け入れて void タイプを返すことはできません。FXML ドキュメントのロードプロセスが完了すると、FXML ローダーは initialize() 関数を呼び出します。
  • FXML では、レイアウトペインに子要素として子が含まれます。プロジェクトの要件を考慮して、ラベル、ボタン、およびその他の要素を追加できます。

サンプルコード(viewController.java クラス、コントローラークラス):

// Step 1: replace this package name with your package name
package com.mycompany.javafx_fxml_loadexception;

// Step 2: import necessary libraries
import javafx.fxml.FXML;
import javafx.scene.control.Button;

// Step 3: viewController class
public class viewController {
  // define button
  @FXML private Button btTest;

  // define the action when the button is clicked
  @FXML
  public void onBtTestAction() {
    System.out.println("CLICK");
  } // end onBtTestAction method

} // end viewController class

viewController.java クラスは、一部のメンバーで@FXML アノテーションを使用するコントローラークラスです。このアノテーションはコンストラクターとクラスで使用できることに注意してください。

このアノテーションを使用して、プライベートであっても、FXML ローダーがこのメンバーに簡単にアクセスできることを指定します。FXML ローダーが public メンバーを使用する場合は、@FXML アノテーションを使用する必要はありません。

ただし、public メンバーに@FXML を使用してもエラーは発生しません。したがって、すべてのメンバーに注釈を付けるのは良いことです。

次の FXML は、コントローラークラスの onBtTestAction() 関数を Button のイベントハンドラーとして設定します。

<Button fx:id="btTest" layoutX="170.0" layoutY="208.0" mnemonicParsing="false"         onAction="#onBtTestAction" text="Button" />

サンプルコード(App.java クラス、メインクラス):

// Step 1: replace the package name with your package name
package com.mycompany.javafx_fxml_loadexception;

// Step 2: import necessary libraries
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

// Step 3: primary launch class extending the Application class
public class App extends Application {
  /**
   *
   * @param stage
   */
  @Override
  public void start(Stage stage) {
    // load the view.fxml file, add it to the scene and show it
    try {
      Parent parent = FXMLLoader.load(getClass().getResource("/fxml/view.fxml"));
      // create a scene
      Scene scene = new Scene(parent);
      // set scene to a stage
      stage.setScene(scene);
      // show the stage
      stage.show();
    } // end try
    catch (IOException e) {
      e.printStackTrace();
    } // end catch
  } // end start method

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

} // end App class

メインファイルはアプリケーションクラスを拡張し、その抽象メソッド start() をオーバーライドします。start() メソッドでは、view.fxml ファイルをロードし、シーンを作成し、このシーンをステージに設定して、そのステージを表示します。

出力(Button をクリックするたびに、IDE のコンソールに CLICK という単語が出力されます):

JavaFX fxml ロード例外の解決策-出力

次のスクリーンショットを確認して、各ファイルを正しい場所に配置します。

JavaFX fxml ロード例外の解決策-ファイルディレクトリ

著者: Mehvish Ashiq
Mehvish Ashiq avatar Mehvish Ashiq avatar

Mehvish Ashiq is a former Java Programmer and a Data Science enthusiast who leverages her expertise to help others to learn and grow by creating interesting, useful, and reader-friendly content in Computer Programming, Data Science, and Technology.

LinkedIn GitHub Facebook

関連記事 - Java JavaFX