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
という単語が出力されます):
次のスクリーンショットを確認して、各ファイルを正しい場所に配置します。