Lösung für die JavaFX FXML Load Exception
Dieses Tutorial informiert über die Gründe, die die JavaFX FXML-Ladeausnahme verursachen, und bietet eine schnelle Lösung.
Ursachen für die Ausnahme beim Laden von JavaFX FXML
Der erste Grund für das Erhalten der JavaFX FXML-Ladeausnahme ist, wenn der Pfad zu einer FXML-Datei für einen Loader nicht korrekt angegeben ist. Der Pfad /fxml/view.fxml
verweist auf eine Datei view.fxml
in einem Ordner namens fxml
, der sich im Ordner resources
befindet, d. h. auf dem classpath
.
Der Aufruf getClass().getResource()
ruft zur Laufzeit ein Objekt classloader
auf, das nach dem classpath
einer ihm übergebenen Ressource sucht. Auf diese Weise findet es den Ordner fxml
und die Datei view.fxml
in diesem Ordner.
Der zweite Grund kann eine nicht übereinstimmende Komponenten-ID sein, was bedeutet, dass wir möglicherweise eine Komponenten-ID in unserer Controller
-Datei aktualisiert, aber vergessen haben, diese ID in der FXML-Datei zu ändern (oder umgekehrt). In diesem Fall wäre der Controller
nicht in der Lage, diese Komponente in der view.fxml
-Datei zu verlinken.
Sehen Sie sich den folgenden Abschnitt an, um ein klares Verständnis zu haben.
Auf der Datei Controller
:
@FXML
Button btnName1
Auf der FXML View
-Datei:
fx:id="btnName_1"
Im Folgenden finden Sie die Lösung für diese beiden Gründe.
Lösung für die JavaFX FXML-Ladeausnahme
Um diese Anwendung auszuführen, verwenden wir Java 18, JavaFX 13 und NetBeans IDE Version 13. Sie können alle nach Ihrer Wahl verwenden.
Beispielcode (Datei view.fxml
, die Ansichtsdatei):
<!--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>
Es folgt die Schritt-für-Schritt-Erklärung des obigen Codes.
-
Wir schreiben eine XML-Deklaration, indem wir die Version und Kodierung beschreiben.
-
Importieren Sie alle erforderlichen Java-Typen in FXML.
-
Wir verwenden das Tag
AnchorPane
, um das Namespace-Präfixfx
zu deklarieren. Dieses Tag ermöglicht es, die Kanten der untergeordneten Knoten mit dem Versatz von einer Kante des Ankerbereichs zu verankern.Wenn im Ankerbereich eine Polsterung oder ein Rand vorhanden ist, werden die Versätze von den Innenkanten dieser Einfügungen aus gemessen. Das
AnchorPane
-Tag hat verschiedene Eigenschaften, die unten mit einer kurzen Erklärung aufgeführt sind.- Die Eigenschaften
prefHeight
undprefWidth
können verwendet werden, um die berechnete bevorzugte Höhe und Breite der Region zu überschreiben. - In FXML wird der
fx:controller
verwendet, um den Controller auf einemroot
-Element anzugeben. Denken Sie daran, dass wir einen Controller pro FXML-Dokument haben dürfen und dieser imroot
-Element angegeben werden muss.
Was ist das
root
-Element in diesem Code? DasAchnorPane
-Tag ist dasroot
-Element für dieses Codebeispiel, das ein Objekt der obersten Ebene in einem Objektdiagramm des FXML-Dokuments ist.Alle UI-Elemente werden diesem Element hinzugefügt. Darüber hinaus müssen wir auch die Regeln kennen, die ein Verantwortlicher erfüllen muss; Diese Regeln sind unten aufgeführt:
- Ein Controller wird durch den
FXML
-Loader instanziiert. - Ein Controller muss den öffentlichen Konstruktor
no-args
haben. DerFXML
-Loader könnte es nicht instanziieren, wenn es nicht vorhanden ist, was zu einer Ausnahme beim Laden führen würde. - Ein Controller kann zugängliche Funktionen enthalten, die auch als Ereignishandler in FXML angegeben werden können.
- Der
FXML
-Controller sucht automatisch nach zugänglichen Instanzvariablen eines Controllers. Wenn der Name der zugänglichen Instanzvariablen mit dem Attributfx:id
eines Elements übereinstimmt, wird automatisch eine Objektreferenz aus dem FXML in eine Controller-Instanzvariable kopiert.
Diese Funktion macht die Referenzen der UI-Elemente in FXML für den Controller zugänglich. Dann wäre der Controller in der Lage, sie zu verwenden.
- Ein Controller kann auch auf die Funktion
initialize()
zugreifen, die keine Argumente akzeptieren darf und den Typvoid
zurückgibt. Sobald der Ladevorgang des FXML-Dokuments abgeschlossen ist, ruft derFXML
-Loader dieinitialize()
-Funktion auf.
- Die Eigenschaften
-
In FXML enthalten die Layoutfenster die untergeordneten Elemente als untergeordnete Elemente. Unter Berücksichtigung der Projektanforderungen können wir Beschriftungen, Schaltflächen und andere Elemente hinzufügen.
Beispielcode (Klasse viewController.java
, die Controller-Klasse):
// 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
Die Klasse viewController.java
ist eine Controller-Klasse, die bei einigen Mitgliedern die Annotation @FXML
verwendet. Denken Sie daran, dass diese Anmerkung für Konstruktoren und Klassen verwendet werden kann.
Mit dieser Anmerkung geben wir an, dass der FXML
-Loader problemlos auf dieses Mitglied zugreifen kann, auch wenn es privat
ist. Wir müssen die Annotation @FXML
nicht verwenden, wenn der FXML
-Loader ein öffentliches
Mitglied verwendet.
Die Verwendung von @FXML
für ein öffentliches
Mitglied löst jedoch keinen Fehler aus. Es ist also gut, jedes Mitglied zu kommentieren.
Das folgende FXML
setzt die Funktion onBtTestAction()
einer Controller-Klasse als Eventhandler für den Button
:
<Button fx:id="btTest" layoutX="170.0" layoutY="208.0" mnemonicParsing="false" onAction="#onBtTestAction" text="Button" />
Beispielcode (Klasse App.java
, die Hauptklasse):
// 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
Die Hauptdatei erweitert
die Klasse Application
und überschreibt ihre abstrakte Methode start()
. In der Methode start()
laden wir die Datei view.fxml
, erstellen eine Szene, setzen diese Szene auf eine Bühne und zeigen diese Bühne an.
OUTPUT (druckt das Wort CLICK
auf der IDE-Konsole, wenn wir auf den Button
klicken):
Überprüfen Sie den folgenden Screenshot, um jede Datei an der richtigen Stelle zu platzieren: