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 を変更し忘れた(またはその逆)ことを意味します。この場合、Controller は view.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 という単語が出力されます):

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

