I am building a JavaFX which has two windows: a signin window and a register window. The fxml file of the former has a "username" label and text field, a "password" label and text field, a "signin" button, a "close" button and a hyperlink that reads "or create a new user". I want that when users click on the hyperlink, a registration window pop-up with labels and text fields asking for the user to enter a user name, password, first name, etc.
I have a Login.fxml file and a LoginController.java file for the sign in window. And for the registration window I have a CreateUser.fxml file and a CreateUSerController.java file.
My problem is how to load the CreateUser.fxml file (and make the registration window pop-up) from the LoginController.java file. I handle the clicking on the "or create a new user" hyperlink event in LoginController.java, and basically the result I expect of the handling is to make the registration window to pop-up. I get a runtime error.
When I click on the "or create a new user" hyperlink in the login window I get the following error: The Eclipse debugger says "Thread[JavaFX Application Thread](Suspended(uncaught exception RuntimeException))". Also, when I check the value of the variables during execution there is a "runWithoutRenderLock() is throwing", and its value is RuntimeException. Also says that its cause is a "InvocationTargetException", and that the cause of this exception is a "null". Also, a "QuantumToolkit.class" tab appears in eclipse with the message "Source not found" "The JAR file ... has no source attachment". It also has a clickable button that reads "Attach source"
To load "CreateUser.fxml" from "LoginController.java" I used a handler which tries to load the fxml file with this line of code: "root = FXMLLoader.<Parent>load(CreateUserController.class.getResource("CreateUser.fxml"));". Here is where the exception occurs
Please find below my Main class which is where I load the "Login.fxml" file, the "Login.fxml", "LoginController.java", "CreateUser.fxml" and CreateUSerController.java files. Also, an image of my file structure.
File structure src /application -Main.java /controller -LoginController.java -CreateUserController.java /model /view -Login.fxml -CreateUser.fxml -module-info.java
Main.java
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
@Override
public void start(Stage signinStage) throws IOException {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("/view/Login.fxml"));
Scene scene = new Scene(root,400,400);
signinStage.setTitle("Welcome to MyHEalth");
signinStage.setScene(scene);
signinStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
launch(args);
}
}
Login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Hyperlink?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<BorderPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.LoginController">
<center>
<VBox alignment="CENTER" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="400.0" BorderPane.alignment="CENTER">
<children>
<Label maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="21.0" prefWidth="300.0" text="Username">
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<TextField fx:id="userNameField" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="300.0">
<VBox.margin>
<Insets bottom="20.0" />
</VBox.margin>
</TextField>
<Label prefHeight="17.0" prefWidth="300.0" text="Password">
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<TextField fx:id="passwordField" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="300.0" />
<BorderPane prefHeight="100.0" prefWidth="200.0">
<center>
<HBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="30.0" prefWidth="170.0" BorderPane.alignment="CENTER">
<children>
<Button fx:id="signinButton" maxWidth="-Infinity" mnemonicParsing="false" onAction="#signin" prefWidth="70.0" text="Sign in" />
<Button fx:id="closeButton" alignment="CENTER" maxWidth="-Infinity" mnemonicParsing="false" onAction="#close" prefWidth="60.0" text="Close" textAlignment="RIGHT">
<HBox.margin>
<Insets left="40.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</center>
<bottom>
<Hyperlink fx:id="newUserLink" onAction="#openNewUserWindow" text="or create new user" BorderPane.alignment="CENTER" />
</bottom>
</BorderPane>
</children>
</VBox>
</center>
</BorderPane>
LoginController.java
package controller;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import model.User;
public class LoginController {
@FXML
private Button closeButton;
@FXML
private Hyperlink newUserLink;
@FXML
private TextField passwordField;
@FXML
private Button signinButton;
@FXML
private TextField userNameField;
private Stage stage;
private Parent root;
@FXML
void signin(ActionEvent event) {
passwordField.getText();
userNameField.getText();
User user = new User(passwordField.getText(), "first name", "last name", userNameField.getText(), "imagepath");
//still have to get the rest of the information from the database
System.out.print(user.getProfile().getFirstName());//debugging message
}
@FXML
void close(ActionEvent event) {
System.out.print("Thanks for visiting MyHealth. Bye");
System.exit(0);
}
@FXML
void openNewUserWindow(ActionEvent event) {
try {
System.out.print("1st line Inside 'try' block of 'openNewUserWindow' in LoginController");
//System.out.println("\nJust after FXMLLoader Inside 'try' block of 'openNewUserWindow' in LoginController");
root = FXMLLoader.<Parent>load(CreateUserController.class.getResource("CreateUser.fxml"));
//System.out.print("last line Inside 'try' block of 'openNewUserWindow' in LoginController");
}
catch(IOException e){
System.out.print("Problem getting 'CreateUSer.fxml'");
}
Stage createUserStage = new Stage();
Scene createUserScene = new Scene(root, 400, 400);
createUserStage.setScene(createUserScene);
createUserStage.setTitle("Create a new user");
createUserStage.show();
}
}
CreateUser.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.CreateUserController">
<children>
<VBox layoutY="30.0" prefHeight="440.0" prefWidth="400.0">
<children>
<ImageView fitHeight="82.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true">
<VBox.margin>
<Insets left="150.0" top="10.0" />
</VBox.margin>
</ImageView>
<Label fx:id="clickImage" text="Click to select profile picture" textFill="#00000093">
<VBox.margin>
<Insets bottom="20.0" left="125.0" />
</VBox.margin>
</Label>
<Label text="Username">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="userName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="First name">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="firstName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="Last name">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="lastName" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<Label text="Password">
<VBox.margin>
<Insets bottom="5.0" left="50.0" />
</VBox.margin>
</Label>
<TextField fx:id="password" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="280.0">
<VBox.margin>
<Insets bottom="10.0" left="50.0" />
</VBox.margin>
</TextField>
<VBox prefHeight="200.0" prefWidth="100.0">
<children>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="createButton" mnemonicParsing="false" onAction="#create" text="Create user">
<HBox.margin>
<Insets left="100.0" top="15.0" />
</HBox.margin>
</Button>
<Button fx:id="closeButton" mnemonicParsing="false" onAction="#close" text="Close">
<HBox.margin>
<Insets left="30.0" top="15.0" />
</HBox.margin>
</Button>
</children>
</HBox>
<Label fx:id="createdLabel" text="Created user" textFill="#2b784f">
<VBox.margin>
<Insets left="125.0" top="20.0" />
</VBox.margin>
</Label>
</children>
</VBox>
</children>
</VBox>
</children>
</AnchorPane>
CreateUSerController.java
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class CreateUserController {
@FXML
private Label clickImage;
@FXML
private Button closeButton;
@FXML
private Button createButton;
@FXML
private Label createdLabel;
@FXML
private TextField firstName;
@FXML
private TextField lastName;
@FXML
private TextField password;
@FXML
private TextField userName;
@FXML
void close(ActionEvent event) {
}
@FXML
void create(ActionEvent event) {
}
}
First of all, I personally prefer to instantiate a new FXMLLoader instance to load a fxml file. Then you can also specify a location and some other kind of stuff like a controller factory. You can lookup the setter methods here: https://docs.oracle.com/javase/8/javafx/api/javafx/fxml/FXMLLoader.html
But in this case your only mistake is that you load the fxml from the wrong class location. When you use "CreateUserController.class.getResource("CreateUser.fxml")", it will try to find the fxml file in the same directory like the class. You have to use another path like you did before with the login fxml file. ("/view/CreateUser.fxml")
I hope that helps.