javajavafxfxml

Cannot invoke "javafx.scene.control.Label.setText(String)" because "this.nameLabel" is null


It's my first time here but here goes:

I have a JavaFX application that changes the FXML UI labels dynamically.

I want to pass the details from the MainController class to the interface but I get an error saying the nameLabel is null. I investigated why and it's using the main thread. I put it in a Platform.runLater that was recommended to me but the message remains. This in the compareFingerprint method of MainController.

Can anyone help?

This is how I'm loading the controller from MainApp.java

package huellatorniquete;

import com.digitalpersona.uareu.Reader;
import huellatorniquete.models.HuellaResponse;
import huellatorniquete.models.User;
import huellatorniquete.services.ApiService;
import huellatorniquete.databaseMethods.DataInserter;
import huellatorniquete.controllers.MainController;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class HuellaTorniquete extends Application {

    private static final Logger LOGGER = Logger.getLogger(HuellaTorniquete.class.getName());
    private static String idSucursal = "4";
    private List<User> userData = new ArrayList<>();

    @Override
    public void start(Stage primaryStage) throws Exception {
        consumegetDataUser();

        Parent root = FXMLLoader.load(getClass().getResource("/HuellaTorniquete/views/mainview.fxml"));
        
        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("/HuellaTorniquete/css/style.css").toExternalForm());
        
        primaryStage.setTitle("Huella Torniquete");
        primaryStage.setScene(scene);
        primaryStage.setMaximized(true);
        primaryStage.show();
        
        userData = DataInserter.geth2InfoUser();
        
        MainController.convertHuellas(userData);
        System.out.println("Lista con fmd desde main: "+userData);
        System.out.println("Tamaño de lista de FMD desde main: "+userData.size());
        
        
            MainController mc = new MainController();

        mc.compareFingerprint(userData);
    }

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

    private static void processArgs(String[] args) {
        if (args.length > 0) {
            try {
                URI uri = new URI(args[0]);
                String query = uri.getQuery();
                if (query != null) {
                    for (String param : query.split("&")) {
                        String[] keyValue = param.split("=");
                        if (keyValue.length > 1 && "idSucursal".equals(keyValue[0])) {
                            idSucursal = keyValue[1];
                            break;
                        }
                    }
                }
            } catch (Exception ex) {
                LOGGER.log(Level.SEVERE, "Error processing arguments", ex);
            }
        }
    }
    
    private void consumegetDataUser(){
       try {
            userData = ApiService.getDataClient(idSucursal);
            if (!userData.isEmpty()) {
                LOGGER.log(Level.INFO, "Data client: {0}", userData);
                System.out.println("tamaño: "+userData.size());
                DataInserter.insertData(userData);
            } else {
                LOGGER.info("No se encontraron huellas");
            }
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Error al obtener las huellas", e);
        } 
    }

}

MainController.java Overview

package huellatorniquete.controllers;

import com.digitalpersona.uareu.Engine;
import com.digitalpersona.uareu.Fid;
import com.digitalpersona.uareu.Fmd;
import com.digitalpersona.uareu.Reader;
import com.digitalpersona.uareu.Reader.ReaderStatus;
import com.digitalpersona.uareu.ReaderCollection;
import com.digitalpersona.uareu.UareUException;
import com.digitalpersona.uareu.UareUGlobal;
import huellatorniquete.models.User;
import huellatorniquete.services.ApiService;
import huellatorniquete.databaseMethods.DataInserter;
import java.util.ArrayList;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

import com.fazecast.jSerialComm.*;
import huellatorniquete.HuellaTorniquete;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import javax.swing.SwingWorker;

public class MainController {
    
    List<User> userData = new ArrayList<>();
    SerialPort seleccionado = null;  // Inicializamos como null
    HuellaTorniquete ht = new HuellaTorniquete();
    String audioFilePath = "src/huellatorniquete/sounds/Success.mp3"; // Cambia por la ruta de tu archivo
    String audioFilePath2 = "src/huellatorniquete/sounds/Error.mp3";

    // Cargar el archivo de audio
        Media soundSuccess = new Media(Paths.get(audioFilePath).toUri().toString());
        Media soundError = new Media(Paths.get(audioFilePath2).toUri().toString());
        
        private MediaPlayer mediaPlayerSuccess;
        private MediaPlayer mediaPlayerError;
    
    @FXML
    private Label labelMotivacion;
    @FXML
    private Button botonClick;
    String frase = "";
    
    @FXML
    private TextField buscarTextField;
    
    @FXML
    private Label nameLabel;
   
    @FXML
    private Label branchLabel;
    
    @FXML
    private Label membershipLabel;
    
    @FXML
    private Label durationLabel;
    
    @FXML
    private Label startDateLabel;
    
    @FXML
    private Label endDateLabel;
    
    @FXML
    private Label membershipStatusLabel;
    
    @FXML
    private VBox paneleft;

    @FXML
    private void initialize() {
        buscarTextField.textProperty().addListener((observable, oldValue, newValue) -> {
            if (!newValue.matches("\\d*")) {
                buscarTextField.setText(newValue.replaceAll("[^\\d]", ""));
            }
        });
        
        getFrase();
        labelMotivacion.setText(frase);
        
        
        
        userData = DataInserter.geth2InfoUser();
        /*System.out.println("Lista de usuarios cargada: " + userData);
        System.out.println("Tamaño antes de convertirla a FMD controller: "+userData.size());*/

        
        convertHuellas(userData);
        System.out.println("Lista con fmd: "+userData);
        System.out.println("Tamaño de lista FMD: "+userData.size());
        
        
        getPort();
    
    
    
    mediaPlayerSuccess = new MediaPlayer(soundSuccess);
    mediaPlayerError = new MediaPlayer(soundError);
    
    
    
    
    System.out.println("Ruta de éxito: " + Paths.get(audioFilePath).toUri().toString());
    System.out.println("Ruta de error: " + Paths.get(audioFilePath2).toUri().toString());
        
 
    
    private void getPort() {
        SerialPort[] ports = SerialPort.getCommPorts();
        seleccionado = null; // Reset seleccionado antes de buscar
        
        for (SerialPort port : ports) {
            System.out.println("names ports: " + port.getDescriptivePortName());
            if (port.getDescriptivePortName().contains("USB-SERIAL")) {
                seleccionado = port;
                System.out.println("seleccionado puerto: " + seleccionado);
                break;
            }
        }
        
        if (seleccionado == null) {
            System.out.println("No se encontró ningún puerto USB-SERIAL");
        }
    }

    private void getFrase(){
        try {
            frase = ApiService.getFrases();
            if (!frase.isBlank()) {
                System.out.println("Frase obtenida: " + frase);
            } else {
                System.out.println("No se encontró frase");
            }
        } catch (Exception e) {
            System.out.println("Error al obtener la frase: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    @FXML
    private void getIdToSearch() {
        System.out.println("Iniciando búsqueda...");
        String numero = buscarTextField.getText();
        System.out.println("Número a buscar: " + numero);

        boolean encontrado = false;

        if (!userData.isEmpty()) {
            for (User user : userData) {
                if (user.getEstafeta().equals(numero)) {
                    System.out.println("Usuario encontrado: " + user);
                    nameLabel.setText(user.getNombre());
                    branchLabel.setText(user.getSucursal());
                    membershipLabel.setText(user.getMembresia());
                    durationLabel.setText(user.getDuracion().toString());
                    startDateLabel.setText(user.getFechaInicio());
                    endDateLabel.setText(user.getFechaFin());
                    encontrado = true;
                    if(user.getStatus().equalsIgnoreCase("Activo") && user.getDuracion() >= 10){
                        mediaPlayerSuccess.stop();  // Detener si está reproduciendo
                        mediaPlayerSuccess.seek(Duration.ZERO);  // Reiniciar al inicio
                        mediaPlayerSuccess.play();
                        membershipStatusLabel.setText("Membresia Activa");
                        //enviarSeñalApertura("COM7");
                        //enviarATodasLosPuertos();
                        if (seleccionado != null) {
                            enviarSeñalApertura(seleccionado.getSystemPortName());
                            enviarDato(seleccionado, 1);
                            System.out.println("Puerto: " + seleccionado);
                        } else {
                            System.out.println("El puerto seleccionado es nulo. Verifica la selección del puerto.");
                        }
                        paneleft.setStyle("-fx-background-color: #98ff96;");
                    } else if(user.getStatus().equalsIgnoreCase("Activo") && user.getDuracion() == 1) {
                        mediaPlayerSuccess.stop();
                        mediaPlayerSuccess.seek(Duration.ZERO);
                        mediaPlayerSuccess.play();                        
                        membershipStatusLabel.setText("Activo - Hoy finaliza la membresia");
                        paneleft.setStyle("-fx-background-color: yellow;");
                        enviarSeñalApertura(seleccionado.getSystemPortName()); // Aquí envías la señal
                        enviarDato(seleccionado,1);
                    } else if(user.getStatus().equalsIgnoreCase("Desactivado")){
                        mediaPlayerError.stop();
                        mediaPlayerError.seek(Duration.ZERO);
                        mediaPlayerError.play();
                        membershipStatusLabel.setText("Sin membresia");
                        paneleft.setStyle("-fx-background-color: red;");
                    }
                    break;
                }
            }
            if (!encontrado) {
                System.out.println("Usuario no encontrado");
                nameLabel.setText("No encontrado");
                branchLabel.setText("No encontrado");
                membershipLabel.setText("No encontrado");
                    durationLabel.setText("No encontrado");
                    startDateLabel.setText("No encontrado");
                    endDateLabel.setText("No encontrado");
            }
        } else {
            System.out.println("La lista de usuarios está vacía");
        }
    }
    
    
     public static void enviarSeñalApertura(String portName) {
        SerialPort port = SerialPort.getCommPort(portName);
        
        if (port.openPort()) {
            try {
                port.setComPortParameters(9600, 8, 1, SerialPort.NO_PARITY);
                port.setComPortTimeouts(SerialPort.TIMEOUT_WRITE_BLOCKING, 0, 0);

                byte[] signal = "1".getBytes();
                int bytesWritten = port.writeBytes(signal, signal.length);

                if (bytesWritten == signal.length) {
                    System.out.println("Señal enviada exitosamente");
                } else {
                    System.out.println("Error al enviar la señal");
                }
            } finally {
                port.closePort();
            }
        } else {
            System.out.println("No se pudo abrir el puerto " + portName);
        }
    }

   
    public void enviarATodasLosPuertos() {
    Task<Void> task = new Task<Void>() {
        @Override
        protected Void call() {
            SerialPort[] ports = SerialPort.getCommPorts();
            System.out.println("Puertos disponibles: " + ports.length);
            for (SerialPort port : ports) {
                System.out.println("Intentando enviar señal al puerto: " + port.getSystemPortName());
                enviarSeñalApertura(port.getSystemPortName());
            }
            return null;
        }
    };

    // Ejecutar el task en un hilo separado
    new Thread(task).start();
}
    
    
    public static void enviarDato(SerialPort puerto, int dato) {
    if (puerto == null) {
        System.out.println("Error: El puerto es nulo.");
        return;
    }

    if (!puerto.isOpen() && !puerto.openPort()) {
        System.out.println("Error: No se pudo abrir el puerto " + puerto.getSystemPortName());
        return;
    }

    try {
        puerto.setComPortParameters(9600, 8, 1, SerialPort.NO_PARITY);
        puerto.setComPortTimeouts(SerialPort.TIMEOUT_WRITE_BLOCKING, 0, 0);

        byte[] data = {(byte) dato};  // Convertimos el entero a un byte
        int bytesWritten = puerto.writeBytes(data, data.length);

        if (bytesWritten == data.length) {
            System.out.println("Dato enviado exitosamente: " + dato);
        } else {
            System.out.println("No se pudo enviar el dato completo. Bytes enviados: " + bytesWritten + " de " + data.length);
        }

        Thread.sleep(100);  // Pequeña pausa para asegurar que el dato se envíe completamente
        puerto.flushIOBuffers(); // Correcto
    } catch (Exception e) {
        System.out.println("Error al enviar el dato: " + e.getMessage());
        e.printStackTrace();
    } finally {
        if (puerto.isOpen()) {
            puerto.closePort();
            System.out.println("Puerto cerrado.");
        }
    }
}
    
    //FINGERPRINT READER
    public static Reader getReaders(){
    Reader reader = null;
    try {
        // Crear una instancia de ReaderCollection
        ReaderCollection readers = UareUGlobal.GetReaderCollection();

        // Actualizar la lista de lectores
        readers.GetReaders();

        // Asegurarse de que hay al menos un lector
        if (readers.size() > 0) {
            // Obtener el primer lector
            System.out.println("Hay lectores disponibles");
            reader = readers.get(0);
            String Lector = reader.GetDescription().name;
            System.out.println("El lector es: "+Lector);
            reader.Open(Reader.Priority.EXCLUSIVE);
        }else {
            System.out.println("No se encontraron lectores");
        }
    }
    catch (UareUException e) {
        e.printStackTrace();
    }
    return reader;
}
    
    
    public void compareFingerprint(List<User> userData) {
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                try {
                    ReaderCollection readers = UareUGlobal.GetReaderCollection();
                    readers.GetReaders();
                    if (readers.size() > 0) {
                        Reader reader = readers.get(0);
                        reader.Open(Reader.Priority.EXCLUSIVE);
                        
                        while (!isCancelled()) {
                            try {
                                Fmd capturedFmd = capturarHuella(reader);
                                System.out.println("capturada: " + capturedFmd);
                                
                                if (capturedFmd != null) {
                                    boolean huellaEncontrada = false;
                                    for (User user : userData) {
                                        if (user.getHuellaFmd() != null) {
                                            try {
                                                int score = UareUGlobal.GetEngine().Compare(capturedFmd, 0, user.getHuellaFmd(), 0);
                                                int threshold = 100000;
                                                
                                                if (score < threshold) {
                                                    System.out.println("Se encontró una huella coincidente para el usuario: " + user.getNombre());
                                                    huellaEncontrada = true;
                                                    System.out.println("Valor de Sucursal: " + user.getSucursal());
                                                    //branchLabel.setText(user.getSucursal());
                                                    
                                                    // Primero actualizamos el puerto
                                                    Platform.runLater(() -> {
                                                        actualizarDatosUsuario(user);
                                                    });
                                                    
                                                    //Thread.sleep(2000);
                                                    break;
                                                }
                                            } catch (UareUException e) {
                                                System.err.println("Error al comparar huellas: " + e.getMessage());
                                            }
                                        }
                                    }
                                    if (!huellaEncontrada) {
                                        System.out.println("No se encontró ninguna huella coincidente.");
                                        Thread.sleep(1000);
                                    }
                                } else {
                                    System.out.println("No se pudo capturar la huella.");
                                    Thread.sleep(500);
                                }
                            } catch (Exception e) {
                                System.err.println("Error en el ciclo de captura: " + e.getMessage());
                                Thread.sleep(1000);
                            }
                        }
                        
                        reader.Close();
                    } else {
                        System.out.println("No se encontraron lectores de huellas dactilares.");
                    }
                } catch (UareUException e) {
                    System.err.println("Error: " + e.getMessage());
                }
                return null;
            }
        };
        
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

     // Método para actualizar los datos del usuario y gestionar el puerto
     private void actualizarDatosUsuario(User user) {
        try {
            getPort(); // Actualiza el puerto seleccionado

            if (seleccionado != null && user.getStatus().equalsIgnoreCase("Activo")) {
                System.out.println("Es activo pasa");
                enviarSeñalApertura(seleccionado.getSystemPortName());
                enviarDato(seleccionado, 1);
                System.out.println("Es activo pasa la señal");

                // Actualiza los labels con la información del usuario
                nameLabel.setText(user.getNombre());
                nameLabel.applyCss();
                nameLabel.layout();
                System.out.println("Es activo pasa el nombre");
                branchLabel.setText(user.getSucursal());
                membershipLabel.setText(user.getMembresia());
                durationLabel.setText(user.getDuracion().toString());
                startDateLabel.setText(user.getFechaInicio());
                endDateLabel.setText(user.getFechaFin());
                membershipStatusLabel.setText("Membresía Activa");

                // Cambia el color del panel si la membresía es válida
                paneleft.setStyle("-fx-background-color: #98ff96;");
                mediaPlayerSuccess.stop();
                mediaPlayerSuccess.seek(Duration.ZERO);
                mediaPlayerSuccess.play();
            } else {
                System.out.println("Usuario no activo o puerto no disponible.");
                membershipStatusLabel.setText("Usuario desactivado");
                paneleft.setStyle("-fx-background-color: red;");
                mediaPlayerError.stop();
                mediaPlayerError.seek(Duration.ZERO);
                mediaPlayerError.play();
            }
        } catch (Exception e) {
            System.err.println("Error al actualizar datos del usuario: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static Fmd capturarHuella(Reader reader) {
        try {
            Reader.CaptureResult captureResult = reader.Capture(
                Fid.Format.ANSI_381_2004,
                Reader.ImageProcessing.IMG_PROC_DEFAULT,
                500,
                -1
            );
            if (captureResult != null && captureResult.quality == Reader.CaptureQuality.GOOD) {
                return UareUGlobal.GetEngine().CreateFmd(
                    captureResult.image,
                    Fmd.Format.ANSI_378_2004
                );
            }
        } catch (UareUException e) {
            System.err.println("Error al capturar la huella: " + e.getMessage());
        }
        return null;
    }

    public static void convertHuellas(List<User> dataUser) {
    if (!dataUser.isEmpty()) {
        for (User u : dataUser) {
            String huella = u.getHuella();
            if (!"".equals(huella)) {
                try {
                    // Usar el método decodificarFMD para convertir la huella
                    Fmd fmd = decodificarFMD(huella);
                    
                    if (fmd != null) {
                        // Establecer el Fmd en el objeto User
                        u.setHuella(fmd);
                        System.out.println("Huella a fmd jijiji: "+u.getHuellaFmd());
                    } else {
                        System.err.println("No se pudo decodificar la huella para el usuario " + u.getNombre());
                    }
                } catch (Exception e) {
                    System.err.println("Error al convertir la huella para el usuario " + u.getNombre() + ": " + e.getMessage());
                }
            }
        }
    }
}

    public static Fmd decodificarFMD(String base64) {
        try {
            // Decodificar la cadena Base64 a un arreglo de bytes
            byte[] data = Base64.getDecoder().decode(base64);

            // Crear un objeto FMD a partir del arreglo de bytes
            Fmd fmd = UareUGlobal.GetImporter().ImportFmd(data, Fmd.Format.ANSI_378_2004, Fmd.Format.ANSI_378_2004);

            return fmd;
        } catch (Exception e) {
            e.printStackTrace();
            return null; // En caso de error, retornar null
        }
    }
}

Overview of mainview.fxml

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

<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.geometry.Insets?>

<GridPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/17"
          fx:controller="huellatorniquete.controllers.MainController" alignment="CENTER">
    <columnConstraints>
        <ColumnConstraints percentWidth="50" />
        <ColumnConstraints percentWidth="50" />
    </columnConstraints>
    <rowConstraints>
        <RowConstraints vgrow="ALWAYS" />
    </rowConstraints>
    <children>
        <!-- Panel izquierdo (50% de ancho) -->
        <VBox GridPane.columnIndex="0" styleClass="left-pane" spacing="20" alignment="TOP_CENTER" fx:id="paneleft">
            <padding>
                <Insets top="20" right="30" bottom="30" left="30" />
            </padding>
            <HBox spacing="10" alignment="CENTER">
                <TextField fx:id="buscarTextField" promptText="Buscar" HBox.hgrow="ALWAYS" />
                <Button text="Buscar" styleClass="search-button" onAction="#getIdToSearch"/>
                <Button text="Actualizar" styleClass="update-button" />
            </HBox>
            <Region VBox.vgrow="ALWAYS" minHeight="20" maxHeight="50" />
            <ImageView fx:id="userPhotoImageView" fitWidth="150" fitHeight="150" preserveRatio="true">
                <Image url="/huellatorniquete/images/logo.jpeg" />
            </ImageView>
            <Label fx:id="idLabel" text="1" styleClass="id-label" />
            <GridPane vgap="20" hgap="30" alignment="CENTER">
                <columnConstraints>
                    <ColumnConstraints percentWidth="50" />
                    <ColumnConstraints percentWidth="50" />
                </columnConstraints>
                <rowConstraints>
                    <RowConstraints vgrow="SOMETIMES" minHeight="30" />
                    <RowConstraints vgrow="SOMETIMES" minHeight="30" />
                    <RowConstraints vgrow="SOMETIMES" minHeight="30" />
                </rowConstraints>
                
                <VBox GridPane.columnIndex="0" GridPane.rowIndex="0" alignment="CENTER">
                    <Label text="Nombre:" styleClass="info-label" />
                    <Label fx:id="nameLabel" text="---" styleClass="info-value" />
                </VBox>
                <VBox GridPane.columnIndex="1" GridPane.rowIndex="0" alignment="CENTER">
                    <Label text="Sucursal:" styleClass="info-label" />
                    <Label fx:id="branchLabel" text="---" styleClass="info-value" />
                </VBox>
                
                <VBox GridPane.columnIndex="0" GridPane.rowIndex="1" alignment="CENTER">
                    <Label text="Membresía:" styleClass="info-label" />
                    <Label fx:id="membershipLabel" text="---" styleClass="info-value" />
                </VBox>
                <VBox GridPane.columnIndex="1" GridPane.rowIndex="1" alignment="CENTER">
                    <Label text="Duración:" styleClass="info-label" />
                    <Label fx:id="durationLabel" text="---" styleClass="info-value" />
                </VBox>
                
                <VBox GridPane.columnIndex="0" GridPane.rowIndex="2" alignment="CENTER">
                    <Label text="Fecha Inicio:" styleClass="info-label" />
                    <Label fx:id="startDateLabel" text="---" styleClass="info-value" />
                </VBox>
                <VBox GridPane.columnIndex="1" GridPane.rowIndex="2" alignment="CENTER">
                    <Label text="Fecha Fin:" styleClass="info-label" />
                    <Label fx:id="endDateLabel" text="---" styleClass="info-value" />
                </VBox>
            </GridPane>
            <Label fx:id="membershipStatusLabel" text="---" styleClass="membership-status" />
        </VBox>
        
        <!-- Panel derecho (50% de ancho) -->
        
    </children>
</GridPane>

Console:

Error al actualizar datos del usuario: Cannot invoke "javafx.scene.control.Label.setText(String)" because "this.nameLabel" is null
java.lang.NullPointerException: Cannot invoke "javafx.scene.control.Label.setText(String)" because "this.nameLabel" is null
    at huellatorniquete.controllers.MainController.actualizarDatosUsuario(MainController.java:642)
    at huellatorniquete.controllers.MainController$2.lambda$call$0(MainController.java:563)
    at javafx.graphics@23.0.1/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:456)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
    at javafx.graphics@23.0.1/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:455)
    at javafx.graphics@23.0.1/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at javafx.graphics@23.0.1/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at java.base/java.lang.Thread.run(Thread.java:1583)

Solution

  • Your problem is that you create a MainController instance in method start of class HuellaTorniquete, i.e.

    MainController mc = new MainController();
    

    You need to use the MainController instance that is created and initialized by FXMLLoader. You can obtain that instance via method getController as follows (in method start of class HuellaTorniquete):

    java.net.URL url = getClass().getResource("/HuellaTorniquete/views/mainview.fxml");
    FXMLLoader loader = new FXMLLoader(url);
    Parent root = loader.load();
    MainController mc = loader.getController();
    

    Do the above rather than what you are currently doing, i.e.

    Parent root = FXMLLoader.load(getClass().getResource("/HuellaTorniquete/views/mainview.fxml"));