1

Tengo un problema con una pequeña app que he creado usando JavaFX, pasa que usando el loader para cargar los .fxml de la aplicación además de cargarlos obtengo instancia del controlador asociado, con el fin de poder manipular algunos detalles de la aplicación. Ha funcionado bien pero he decidido crear una pequeña ventana de carga para la app, y este no me deja obtener arrojando NullPointerException.

El problema no es obtener la excepción, está referido a la manera correcta de cargar los .fxml y controladores en JavaFX

Este error lo obtengo cargando el controlador del loadWindow.fxml, mediante el loader obteniendo la instancia de la clase LOADController mediante getController usando la clase anterior como template. La ruta del archivo es casi la misma de los fxml vecinos, y en cada .fxml existe "fx-controller:"ruta".

feb 02, 2020 5:32:48 PM javafx.fxml.FXMLLoader$ValueElement processValue
WARNING: Loading FXML document with JavaFX API of version 11.0.1 by JavaFX runtime of version 8.0.231
java.lang.NullPointerException
    at application.RuntimeCommand.initializeView(RuntimeCommand.java:57)
    at application.RuntimeCommand.init(RuntimeCommand.java:36)
    at application.Main.start(Main.java:12)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
    at java.lang.Thread.run(Unknown Source)

En la clase a continuación, se cargan los fxml al inicio de la aplicación, y dentro del método loadStage se carga el controlador de cada uno, repito los otros dos controladores cargan perfectamente pero este se ha resistido.

Clase general donde cargo los .fxml

package application;

import java.io.IOException;
import java.util.ArrayList;

import controller.CRUDController;
import controller.GUIController;
import controller.LOADController;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import model.Clock;
import model.TableMovement;
import model.XMLGenerator;

public class RuntimeCommand {

    public static Stage mainWindow, crudWindow, loadWindow;
    public static Clock clock;

    public static CRUDController controllerCRUD;
    public static GUIController controllerGUI;
    public static LOADController controllerLOAD;

    public static ArrayList<TableMovement> dataList = new ArrayList<TableMovement>();

    public static final int GUI = 0, CRUD = 1, LOAD = 2;

    public static void init() {

        initializeLoadWindow();
        initializeView();
        loadXMLFile();  
        initializeClock();

        mainWindow.centerOnScreen();
        controllerLOAD.reset();
        loadWindow.hide();

        mainWindow.showAndWait();
    }

    private static void initializeLoadWindow() {
        loadWindow = loadStage("../view/LoadWindow.fxml", LOAD);
        loadWindow.setResizable(false);
        loadWindow.centerOnScreen();
        loadWindow.initStyle(StageStyle.UNDECORATED);
        loadWindow.show();
    }

    private static void initializeView() {

        controllerLOAD.reset();
        loadWindow.show();

        mainWindow = loadStage("../view/Application.fxml", GUI);
        crudWindow = loadStage("../view/crudWindow.fxml", CRUD);
        crudWindow.setResizable(false);
        mainWindow.setResizable(false);


        mainWindow.setTitle("ChaosLogger by jrv99");

        // close actions
        mainWindow.setOnCloseRequest( (e)-> {
            loadWindow.show();
            controllerLOAD.lblText.setText("Saving data");
            XMLGenerator.generateXMLFromList(controllerGUI.getMovementList());
            controllerLOAD.lblText.setText("Closing");
            loadWindow.hide();
            Platform.exit();
            System.exit(0);
        });

        crudWindow.setOnCloseRequest((e) -> {
            crudWindow.hide();
        });

        controllerLOAD.lblText.setText("Loading movements");
        // load the data getted from the xml file
        controllerGUI.loadList();
    }

    public static Stage loadStage(String path, int mode) {

        Stage stage = null;
        BorderPane root;
        Scene scene;

        try {

            FXMLLoader loader = new FXMLLoader(RuntimeCommand.class.getResource(path));

            switch(mode) {
                case GUI:
                    controllerGUI = loader.<GUIController>getController();
                    break;
                case CRUD:
                    controllerCRUD = loader.<CRUDController>getController();
                    break;
                case LOAD:
                    controllerLOAD = loader.<LOADController>getController();
                    break;
                default: {
                    System.out.println("Modo de controlador no encontrado");
                    root = null;
                }
            }

            root = (BorderPane) loader.load();
            stage = new Stage();
            scene = new Scene(root);
            scene.getStylesheets().add(RuntimeCommand.class.getResource("../view/application.css").toExternalForm());
            stage.setScene(scene);
            stage.getIcons().add(new Image("file:res/appIcon.png"));

        } catch (IOException e) {
            e.printStackTrace();
        }
        return stage;
    }

    private static void initializeClock() {
        controllerLOAD.lblText.setText("Loading time");
        clock = Clock.getInstance();
        clock.start();
    }

    private static void loadXMLFile() {
        controllerLOAD.lblText.setText(controllerLOAD.defaultText+"data");
        loadWindow.show();

        XMLGenerator.loadXMLtoList(dataList);

        //loadWindow.hide();
        controllerLOAD.reset();
    }
}

Controlador de la ventana de carga

package controller;

import java.net.URL;
import java.util.ResourceBundle;

import com.jfoenix.controls.JFXProgressBar;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

public class LOADController implements Initializable {

    public static final String defaultText = "Loading ";

    @FXML public Label lblText;
    @FXML public JFXProgressBar pbLoad;

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        reset();
    }

    public void reset() {
        lblText.setText(defaultText);
        pbLoad.getAccessibleText();
    }

}

FXML asociado

<?xml version="1.0" encoding="UTF-8"?>

<?import com.jfoenix.controls.JFXProgressBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="98.0" prefWidth="396.0" style="-fx-background-color: #000000;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.LOADController">
   <center>
      <BorderPane prefHeight="73.0" prefWidth="396.0" BorderPane.alignment="CENTER">
         <bottom>
            <Label fx:id="lblText" alignment="CENTER" contentDisplay="CENTER" prefHeight="87.0" prefWidth="396.0" style="-fx-text-fill: #ffffff;" text="Cargando ..." BorderPane.alignment="CENTER">
               <font>
                  <Font name="Corbel Light" size="25.0" />
               </font>
            </Label>
         </bottom>
      </BorderPane>
   </center>
   <bottom>
      <JFXProgressBar fx:id="pbLoad" prefHeight="13.0" prefWidth="405.0" style="-fx-background-color: #909090;" BorderPane.alignment="CENTER" />
   </bottom>
</BorderPane>

Clase principal package application;

import javafx.application.Application;
import javafx.stage.Stage;


public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        try {
            RuntimeCommand.init();  
        } catch(Exception e) {
            e.printStackTrace();
        }       
    }

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

Tomar en cuenta que uso una estructura de paquetes: dentro del

->src 
   -> app
   -> controller
   -> model
   -> view

Uso JavaFX API of version 11.0.1 by JavaFX runtime of version 8.0.231, hasta el momento los demas controladores de la aplicacion funcionan segun lo esperado, pero este ha sido la excepción. Trabajo en Eclipse 2019-12 (4.14.0)

  • No queda claro cual de los tres es el que no se carga ¿? Tampoco veo tu clase `Main`. La traza de error refiere el error en `Main`, en el método `start()` en la línea 12. Y habla también de `Unknown source` ... es muy probable que la ruta de alguno de los XML esté mal escrita. – A. Cedano Feb 03 '20 at 00:04
  • He modificado, según las sugerencias de Cedano – Josue Rojas Vega Feb 03 '20 at 00:14
  • No entiendo mucho el lío. ¿Esa es la traza de error completa? Si no lo es, pon la traza completa del error. – A. Cedano Feb 03 '20 at 00:25
  • Es la traza completa, que parte no entiendes para aclarar :) – Josue Rojas Vega Feb 03 '20 at 00:25
  • ¿Todos los xml tienen el atributo `fx:controller=`? ¿Si evitas la llamada de `LOADController` el código funciona? – A. Cedano Feb 03 '20 at 00:26
  • Si todos tienen el atributo, y si este funciona bien, lo dejé claro en la pregunta, la obtención de controladores y carga de los fxml vecinos, o sea antes de agregar la ventana de carga todo funcionaba bien, solo que no sé el porque me arroja null si este esta asociado correctamente – Josue Rojas Vega Feb 03 '20 at 00:36
  • ¿Qué tienes en la carpeta `view`? – A. Cedano Feb 03 '20 at 00:41
  • [Continuemos el debate en el chat](https://chat.stackexchange.com/rooms/104010/discussion-between-a-cedano-and-josue-rojas-vega). – A. Cedano Feb 03 '20 at 00:48

1 Answers1

0

He encontrado el error:

En el metodo loadStage:

try {

            FXMLLoader loader = new FXMLLoader(RuntimeCommand.class.getResource(path));

            switch(mode) {
                case GUI:
                    controllerGUI = loader.<GUIController>getController();
                    break;
                case CRUD:
                    controllerCRUD = loader.<CRUDController>getController();
                    break;
                case LOAD:
                    controllerLOAD = loader.<LOADController>getController();
                    break;
                default: {
                    System.out.println("Modo de controlador no encontrado");
                    root = null;
                }
            }

            root = (BorderPane) loader.load();

A la hora de crear el swith he cambiado de posición cuando se cargar el BorderPane desde el .fxml correspondiente, y he intentado obtener los controladores antes de cargar el archivo provocando que esté no pueda conseguir la instancia del controlador asociado devolviendo NPE. Se soluciona colocando la última del linea donde del código anterior donde se hace el casteo y carga del objeto obtenido del .fxml antes del switch que he definido para cargar el controlador segun el fxml dado. Gracias a A. Cedano que aunque no me ha solucionado el problema mostró interés en resolverlo. Quedaría de la siguiente manera:

try {

            FXMLLoader loader = new FXMLLoader(RuntimeCommand.class.getResource(path));
            root = (BorderPane) loader.load(); // load before to get controllers

            switch(mode) {
                case GUI:
                    controllerGUI = loader.<GUIController>getController();
                    break;
                case CRUD:
                    controllerCRUD = loader.<CRUDController>getController();
                    break;
                case LOAD:
                    controllerLOAD = loader.<LOADController>getController();
                    break;
                default: {
                    System.out.println("Modo de controlador no encontrado");
                    root = null;
                }
            }
BetaM
  • 30,571
  • 7
  • 32
  • 50