Solución a la excepción de carga JavaFX FXML
Este tutorial educa sobre las razones que causan la excepción de carga JavaFX FXML y proporciona una solución rápida.
Razones que causan la excepción de carga JavaFX FXML
La primera razón para obtener la excepción de carga JavaFX FXML es cuando la ruta a un archivo FXML no se especifica correctamente en un cargador. La ruta /fxml/view.fxml
se refiere a un archivo view.fxml
en una carpeta llamada fxml
que reside en la carpeta resources
, es decir, en el classpath
.
La llamada getClass().getResource()
invoca un objeto classloader
en tiempo de ejecución, que busca el classpath
de un recurso que se le pasa. De esta forma, encontrará la carpeta fxml
y el archivo view.fxml
dentro de esa carpeta.
La segunda razón puede ser tener una ID de componente que no coincida, lo que significa que es posible que hayamos actualizado una ID de componente en nuestro archivo Controller
, pero olvidamos cambiar esa ID en el archivo FXML (o viceversa). En este caso, el Controller
no podría vincular ese componente en el archivo view.fxml
.
Consulte el siguiente fragmento para tener una comprensión clara.
En el archivo Controller
:
@FXML
Button btnName1
En el archivo FXML View
:
fx:id="btnName_1"
A continuación se muestra la solución a ambas razones.
Solución a la excepción de carga JavaFX FXML
Para ejecutar esta aplicación, usamos Java 18, JavaFX 13 y NetBeans IDE versión 13. Puede usarlos todos según su elección.
Código de ejemplo (archivo view.fxml
, el archivo de vista):
<!--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>
A continuación se muestra la explicación paso a paso del código anterior.
-
Escribimos una declaración XML describiendo la versión y la codificación.
-
Importe todos los tipos de Java necesarios en FXML.
-
Usamos la etiqueta
AnchorPane
para declarar el prefijo del espacio de nombresfx
. Esta etiqueta permite anclar los bordes de los nodos secundarios al desplazamiento desde un borde del panel de anclaje.Si hay relleno o borde en el panel de anclaje, los desplazamientos se medirán desde los bordes interiores de esos insertos. La etiqueta
AnchorPane
tiene varias propiedades que se enumeran a continuación con una breve explicación.- Las propiedades
prefHeight
yprefWidth
se pueden usar para anular la altura y el ancho preferidos calculados de la región. - En FXML, el
fx:controller
se usa para especificar el controlador en un elementoroot
. Recuerde que se nos permite tener un controlador por documento FXML y debe especificarse en el elementoroot
.
¿Cuál es el elemento
root
en este código? La etiquetaAchnorPane
es el elementoroot
de este ejemplo de código, que es un objeto de nivel superior en un gráfico de objetos del documento FXML.Todos los elementos de la interfaz de usuario se agregarán a este elemento. Además, también necesitamos conocer las reglas que debe cumplir un controlador; estas reglas se enumeran a continuación:
- Un controlador es instanciado por el cargador
FXML
. - Un controlador debe tener el constructor público
no-args
. El cargadorFXML
no podría crear una instancia si no está allí, lo que generaría una excepción en el momento de la carga. - Un controlador puede contener funciones accesibles que también se pueden especificar como controladores de eventos en FXML.
- El controlador
FXML
busca automáticamente las variables de instancia accesibles de un controlador. Si el nombre de la variable de instancia accesible coincide con el atributofx:id
de un elemento, una referencia de objeto del FXML se copiará automáticamente en una variable de instancia del controlador.
Esta función hará que las referencias de los elementos de la interfaz de usuario en el FXML sean accesibles para el controlador. Entonces, el controlador podría usarlos.
- Un controlador también puede acceder a la función
initialize()
, que no debe aceptar argumentos y devolver el tipovoid
. Una vez que se completa el proceso de carga del documento FXML, el cargadorFXML
llama a la funcióninitialize()
.
- Las propiedades
-
En FXML, los paneles de diseño contienen los elementos secundarios como sus elementos secundarios. Teniendo en cuenta los requisitos del proyecto, podemos agregar etiquetas, botones y otros elementos.
Código de ejemplo (clase viewController.java
, la clase del controlador):
// 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
La clase viewController.java
es una clase de controlador que usa la anotación @FXML
en algunos miembros. Recuerde que esta anotación se puede usar en constructores y clases.
Usando esta anotación, especificamos que el cargador FXML
puede acceder fácilmente a este miembro incluso si es privado. No necesitamos usar la anotación @FXML
si el cargador FXML
usa un miembro público.
Sin embargo, usar @FXML
para un miembro público
no genera ningún error. Por lo tanto, es bueno anotar cada miembro.
El siguiente FXML
establece la función onBtTestAction()
de una clase de controlador como controlador de eventos para el Button
:
<Button fx:id="btTest" layoutX="170.0" layoutY="208.0" mnemonicParsing="false" onAction="#onBtTestAction" text="Button" />
Código de ejemplo (clase App.java
, la clase principal):
// 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
El archivo principal extiende la clase Application
y anula su método abstracto start()
. En el método start()
, cargamos el archivo view.fxml
, creamos una escena, configuramos esta escena en un escenario y mostramos ese escenario.
SALIDA (imprime la palabra CLICK
en la consola del IDE cada vez que hacemos clic en el Botón
):
Verifique la siguiente captura de pantalla para colocar cada archivo en la ubicación correcta: