Switch fxml pages without creating new controller - java

I am dealing with JavaFX, as you can see in the picture below, I have a menu (A,B,C,D,E) on the left, all I want to do is that when I click on the menu item, the content of the page change (the red form).
I implemented my code, it works fine visually, but at each time it creates a new controller for each new form. And when it does so I loose the data of my main frame. Here is my Code to explain better.
MainFrame.fxml
<ScrollPane xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.Inhumer.MainController" >
<BorderPane fx:id="myContent" >
<center >
<fx:include fx:id="demandeur" source="Demandeur.fxml" />
</center>
<left>
<fx:include fx:id="menu" source="SideBar_Inhumer.fxml" />
</left>
</BorderPane>
</ScrollPane>
MainController.java
package Controller.Inhumer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.layout.BorderPane;
import java.io.IOException;
import java.util.HashMap;
public class MainController {
HashMap<String, Parent> menuItems;
#FXML
public BorderPane myContent ;
#FXML
DemandeurController demandeurController;
#FXML
MenuController menuController;
#FXML public void initialize() throws IOException {
/*load the content of my forms */
Parent rootDemandeur = new FXMLLoader(getClass().getResource("../../View/Inhumer/Demandeur.fxml")).load();
Parent rootDefunt = new FXMLLoader(getClass().getResource("../../View/Inhumer/Defunt.fxml")).load();
Parent rootEmplacement = new FXMLLoader(getClass().getResource("../../View/Inhumer/Emplacement.fxml")).load();
Parent rootPrestataire = new FXMLLoader(getClass().getResource("../../View/Inhumer/Prestataire.fxml")).load();
Parent rootOperation = new FXMLLoader(getClass().getResource("../../View/Inhumer/Operation.fxml")).load();
menuItems = new HashMap<>();
menuItems.put("demandeur",rootDemandeur); //A
menuItems.put("defunt",rootDefunt); //B
menuItems.put("emplacement",rootEmplacement); //C
menuItems.put("prestataire",rootPrestataire); //D
menuItems.put("operation",rootOperation); //E
System.out.println("Application started");
demandeurController.init(this);
menuController.init(this);
}
}
MenuController.java
package Controller.Inhumer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.layout.BorderPane;
import java.io.IOException;
public class MenuController {
private MainController main;
/*methods called onClick on each item of my menu*/
#FXML
public void goToDemandeur() throws IOException {
main.myContent.setCenter(main.menuItems.get("demandeur"));
}
#FXML
public void goToDefunt() throws IOException {
main.myContent.setCenter(main.menuItems.get("defunt"));
}
#FXML
public void goToEmplacement() throws IOException {
main.myContent.setCenter(main.menuItems.get("emplacement"));
}
#FXML
public void goToPrestataire() throws IOException {
main.myContent.setCenter(main.menuItems.get("prestataire"));
}
#FXML
public void goToOperation() throws IOException {
main.myContent.setCenter(main.menuItems.get("operation"));
}
public void init(MainController mainController) {
main = mainController;
}
}
DemandeurController.java (the controller of the red form)
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class DemandeurController implements Initializable {
public MainController mainController;
/*Onclick action on the button called "suivant"*/
#FXML
public void next() throws IOException {
System.out.println(mainController);
/*print null, because when loading this form mainController will get
null value, and I want to always get the value of mainController
so I can access to its content from this controller*/
}
public void init(MainController mainController) {
this.mainController = mainController;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
I hope that I clarified well the problem, any help? I am blocked here for two days :v

Related

How to open popup window from an other class without button click in javaFX?

So I've got a method called 'popup' in a javaFX controller class which opens a small popup window on top of the actual application window. This method runs without problem if it's assigned to a button in fxml and the button is clicked, but this is not the way I want to use it.
I've got an other class called 'Timer' with a new task (new thread) which is counting down from a certain number, and at a point it will open a popup window with a message. My purpose is to call and run the 'popup' method from this 'Timer' class. When I call the 'popup' method from here, it starts executing, but the popup window doesn't appear at all. (The method call happens as I get the message "in popup" on console from 'popup' method. )
So why does it work when a button click calls 'popup' method from the fxml file and why not when I call it from an other class? Thanks.
Please see the controller class with 'popup' method and the Timer class below (using Gradle in project):
"SceneController" controller class:
package GradleFX;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
//import java.awt.event.ActionEvent;
public class SceneController implements Initializable {
public static String password = "";
protected static int timercount = 20;
#FXML
private Label PWLabel;
#FXML
private Label bottomLabel;
#FXML
private PasswordField PWField;
#FXML
private Label showPWLabel;
protected static Label myBottomLabel;
private static PasswordField myPWField;
private static Label myShowPWLabel;
private static int tries;
#Override
public void initialize(URL location, ResourceBundle resources) {
Timer timerTask = new Timer();
myBottomLabel = bottomLabel;
myPWField = PWField;
myShowPWLabel = showPWLabel;
new Thread(timerTask).start();
}
**/***********************************************************************
/*This method runs if button is pressed in main application,
but can't make it work by calling it from Timer Class */
public void popup() {
System.out.println("in popup");
Stage dialogStage = new Stage();
dialogStage.initModality(Modality.WINDOW_MODAL);
VBox vbox = new VBox(new Text("Hi"), new Button("Ok."));
vbox.setAlignment(Pos.CENTER);
vbox.setPadding(new Insets(15));
dialogStage.setScene(new Scene(vbox));
dialogStage.show();
}
//****************************************************************************
public void showPW() {
myShowPWLabel.setText(myPWField.getText());
}
public void hidePW() {
myShowPWLabel.setText("");
}
public void exit() {
System.exit(0);
}
public void write() {
PWLabel.setText("Mukodik");
}
public void writeInput(String in) {
password = in;
System.out.println("final password text text: " + password);
writeFinally();
}
public void writeFinally() {
System.out.println("This is 'password' : " + password);
//bottomLabel.setText(password);
}
public void bottomLabelWrite() {
bottomLabel.setText(myPWField.getText());
}
public static void setLabel() throws InterruptedException {
myBottomLabel.setText("");
myBottomLabel.setText("Database has been permanently erased.");
//Thread.sleep(3000);
//System.exit(0);
}
public static void noKeyEnteredNote() {
myBottomLabel.setTextFill(Color.BLACK);
myBottomLabel.setText("No key entered. Type Main Key.");
}
public static void rightKey() {
myBottomLabel.setText("Yes, this is the right key.");
}
public static void wrongKey() throws InterruptedException {
tries = MasterKey.numOfTryLeft;
if (tries > 0) {
myBottomLabel.setTextFill(Color.RED);
myBottomLabel.setText("!!!Wrong key!!! You've got " + tries + " tries left!");
}
}
public void simpleTest(String in) {
System.out.println("in simpleTest and in is: " + in);
}
public void getMainKey() throws IOException, InterruptedException {
MasterKey masterKey = new MasterKey();
System.out.println("Inside SceneController");
masterKey.requestKey(myPWField.getText());
}
public void changeScreen(ActionEvent event) throws IOException, InterruptedException {
getMainKey();
if (MasterKey.isRightKey) {
Parent tableViewParent = FXMLLoader.load(getClass().getResource("Menu.fxml"));
Scene tableViewScene = new Scene(tableViewParent);
Stage window = (Stage) ((Node) event.getSource()).getScene().getWindow();
window.setScene(tableViewScene);
window.show();
}
}
}
This is Timer class:
package GradleFX;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
public class Timer extends Task {
private ActionEvent actionEvent;
#Override
protected Integer call() throws Exception {
boolean notCalled = true;
while (SceneController.timercount > 0) {
SceneController sceneController = new SceneController();
System.out.println(SceneController.timercount);
Thread.sleep(1000);
SceneController.timercount--;
if (SceneController.timercount < 19) {
System.out.println("Less than 5");
if(notCalled) {
sceneController.popup();
notCalled = false;
}
}
}
System.exit(0);
return null;
}
}
Add this to your code:
#Override
public void initialize(URL location, ResourceBundle resources) {
Timer timerTask = new Timer();
myBottomLabel = bottomLabel;
myPWField = PWField;
myShowPWLabel = showPWLabel;
new Thread(timerTask).start();
timerTask.setOnFinished(e->{
popup();
});
}

Managing different JavaFX stages through a signle slass

I'm writing a simple JavaFX application that has three Stages: Login, Register (Anmeldung) and Welcome (Anwendung). Sorry for the German namings!
I have created each Stage and it's Scene in an App class and the handling events in a Controller class and the designs in fxml files. I need to implement a MainApp class which has to manage the communication between Login, Anmeldung and Anwendung windows.
The MainApp should initially launch a Login window and then in there if the checkbox is selected, the MainApp should be notified and order the launch of Anmeldung window. After successful registration, the MainApp should close the Anmeldung window and show the Login window again. There, when user logs in, the MainApp should again close the Login window and order a launch for Anwendung window.
I have done the transition between Login and Anmeldung windows by modifying the LoginController, which shouldn't be done there and has to be accomplished via the MainApp.
Additionally the task wants the whole thing to be done with only one launch(args).
LoginController.java:
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Modality;
import javafx.stage.Stage;
import resources.Benutzer;
public class LoginController {
// private static MainApp mainApp;
#FXML
public TextField textFieldUserId;
#FXML
public PasswordField passwordFieldPasswort;
#FXML
public CheckBox checkBoxNeuAnmeldung;
#FXML
public Button buttonEinloggen;
private boolean neuAnmeldung = false;
// public void setCallBack(MainApp mainApp) {
// LoginController.mainApp = mainApp;
// }
#FXML
public void handleButtonEinloggenAction(ActionEvent event) throws Exception {
// Stage stage = (Stage) buttonEinloggen.getScene().getWindow();
if (neuAnmeldung == false) {
Benutzer benutzer = new Benutzer(textFieldUserId.getText(),
passwordFieldPasswort.getText());
Parent anwendungsScene = FXMLLoader
.load(getClass().getResource("/design/Anwendung.fxml"));
Stage anwendungsStage = new Stage();
((Node) (event.getSource())).getScene().getWindow().hide();
anwendungsStage.setScene(new Scene(anwendungsScene));
anwendungsStage.setTitle("Anmeldung");
anwendungsStage.show();
System.out.println(benutzer);
}
// stage.close();
System.out.println("Eingeloggt!");
}
#FXML
public void handleCheckBoxNeuAnmeldungAction(ActionEvent event)
throws Exception {
if (checkBoxNeuAnmeldung.isSelected()) {
neuAnmeldung = true;
Parent anmeldungsScene = FXMLLoader
.load(getClass().getResource("/design/Anmeldung.fxml"));
Stage anmeldungsStage = new Stage();
anmeldungsStage.initModality(Modality.WINDOW_MODAL);
anmeldungsStage
.initOwner(((Node) (event.getSource())).getScene().getWindow());
anmeldungsStage.setScene(new Scene(anmeldungsScene));
anmeldungsStage.setTitle("Anmeldung");
anmeldungsStage.show();
} else
neuAnmeldung = false;
System.out.println("Neu-Anmeldung? " + neuAnmeldung);
}
}
AnmeldungsController.java:
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import resources.Benutzer;
public class AnmeldungsController {
// private static MainApp mainApp;
#FXML
public TextField textFieldUserId;
#FXML
public PasswordField passwordFieldPasswort;
#FXML
public PasswordField passwordFieldWiederholung;
#FXML
public Button buttonAnmelden;
// public void setCallBack(MainApp mainApp) {
// AnmeldungsController.mainApp = mainApp;
// }
#FXML
public void handleButtonAnmeldenAction(ActionEvent event) {
Stage stage = (Stage) buttonAnmelden.getScene().getWindow();
if (passwordFieldPasswort.getText()
.equals(passwordFieldWiederholung.getText())) {
Benutzer benutzer = new Benutzer(textFieldUserId.getText(),
passwordFieldPasswort.getText());
System.out.println(benutzer);
System.out.println("Angemeldet!");
stage.close();
} else {
textFieldUserId.setText("Passwörter stimmen nicht überein!");
System.out.println("Passwörter stimmen nicht überein!");
System.out.println(passwordFieldPasswort.getText() + " != "
+ passwordFieldWiederholung.getText());
}
}
}
AnwendungsController.java:
package controller;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class AnwendungsController {
// private static MainApp mainApp;
#FXML
public Button buttonSchliessen;
// public void setCallBack(MainApp mainApp) {
// AnwendungsController.mainApp = mainApp;
// }
#FXML
public void handleButtonAbbrechenAction(ActionEvent event) {
Stage stage = (Stage) buttonSchliessen.getScene().getWindow();
stage.close();
System.out.println("Fenster Geschlossen!");
}
}
MainApp.java:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MainApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/design/Login.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Benutzerverwaltung");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
Of course the other aspects of the program like Exceptions and creating/reading/deleting users etc is out of the scope of this question!
Here is the basic idea that should get you started:
public class LoginController {
private final ReadOnlyBooleanWrapper loggedIn = new ReadOnlyBooleanWrapper();
public ReadOnlyBooleanProperty loggedInProperty() {
return loggedIn.getReadOnlyProperty() ;
}
public final boolean isLoggedIn() {
return loggedInProperty().get();
}
#FXML
public TextField textFieldUserId;
#FXML
public PasswordField passwordFieldPasswort;
#FXML
public CheckBox checkBoxNeuAnmeldung;
#FXML
public Button buttonEinloggen;
private boolean neuAnmeldung = false;
#FXML
public void handleButtonEinloggenAction(ActionEvent event) throws Exception {
// assuming you verify the login credentials...
loggedIn.set(true);
System.out.println("Eingeloggt!");
}
}
and now in your MainApp you can do:
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MainApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(
getClass().getResource("/design/Login.fxml"));
Parent root = loader.load();
LoginController loginController = loader.getController();
loginController.loggedInProperty().addListener((obs, wasLoggedIn, isNowLoggedIn) -> {
if (isNowLoggedIn) {
// user is now logged in, show welcome screen...
}
});
primaryStage.setTitle("Benutzerverwaltung");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}

JavaFX, closing error window using Button

I have a problem with my basic encrypter application. I want to generate an error window if someone type a string in the keyTextField. And also an event to close the error window using OK Button(Window graphic is loading from fxml file)
I've tried making it as shown below, but without success, i was also using close() method. What are best methods to deal with application control? I am using only MainController and i think it is not good idea. Thank you in advance
`package pl.gumisok.cipherController;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import pl.gumisok.cipherMain.CipherManager;
public class MainController implements Initializable {
CipherManager cipher;
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
System.out.println(contentPaneController);
System.out.println(controlPaneController);
Button encryptButton = controlPaneController.getEncryptButton();
Button decryptButton = controlPaneController.getDecryptButton();
Button okButton = controlPaneController.getOkButton();
TextArea cleanTextArea = contentPaneController.getCleanTextArea();
TextArea cryptTextArea = contentPaneController.getCryptTextArea();
TextField keyTextField = controlPaneController.getKeyTextField();
encryptButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String wiadomosc = cleanTextArea.getText();
System.out.println(wiadomosc);
try {
int key = Integer.parseInt(keyTextField.getText());
System.out.println(key);
} catch (NumberFormatException e) {
System.out.println(e);
FXMLLoader fxmlLoader = new FXMLLoader(getClass()
.getClassLoader().getResource(
"pl/gumisok/cipherView/Error.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Stage sstage = new Stage();
sstage.setOpacity(1);
sstage.setTitle("Error");
sstage.setScene(new Scene(root));
sstage.show();
okButton.setOnAction(x->sstage.hide());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
});
}
}`
your application layer is not good.
you need bind the button action in fxml file to a controller.
Maybe something like this:
Error.fxml:
<AnchorPane xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="controllers.ErrorController">
<children>
<Label text="ERROR!" />
<Button text="close" onAction="#hide" layoutY="15"/>
</children>
</AnchorPane>
ErrorController.java:
public class ErrorController {
private static Stage stage;
private static Parent root;
public ErrorController(){}
public ErrorController(Window owner) throws IOException {
if (root == null)
root = FXMLLoader.load(ClassLoader
.getSystemResource("views/Error.fxml"));
if (stage == null)
stage = new Stage();
//stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
stage.setTitle("Error");
stage.setScene(new Scene(root));
}
public void show() {
stage.show();
}
public #FXML void hide() {
stage.hide();
}
}
And then use it
...
error = new ErrorController(node.getScene().getWindow());
...
try {
int key = Integer.parseInt(keyTextField.getText());
System.out.println(key);
} catch (NumberFormatException e) {
error.show();
}
I hope, I understand the question correct,
here is an example how to create an alert dialog
Alert alert = new Alert(AlertType.INFORMATION);
alert.setTitle("Information Dialog");
alert.setHeaderText(null);
alert.setContentText("I have a great message for you!");
alert.showAndWait();

Java: SetText inside a thread

Can anyone please help me with this:
I have some TextFields that i want to use as a timer (or a clock) so i set the text in a thread that i call inside my controller class.
package application;
import java.net.URL;
import java.util.ResourceBundle;
import org.joda.time.DateTime;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import jdk.nashorn.internal.runtime.FindProperty;
public class MainWindowController extends Thread implements Initializable{
#FXML
private TextField dayText;
#FXML
private TextField monthText;
#FXML
private TextField yearText;
#FXML
private TextField hoursText;
#FXML
private TextField minutesText;
#FXML
private TextField secondsText;
#FXML
private TextField julianDayText;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
this.start();
}
#Override
public void run() {
while(true){
DateTime d = new DateTime(System.currentTimeMillis());
dayText.setText(String.valueOf(d.getDayOfMonth()));
monthText.setText(String.valueOf(d.getMonthOfYear()));
yearText.setText(String.valueOf(d.getYear()));
hoursText.setText(String.valueOf(d.getHourOfDay()));
minutesText.setText(String.valueOf(d.getMinuteOfHour()));
secondsText.setText(String.valueOf(d.getSecondOfMinute()));
}
}
}
I don't know why i get a NullPointerException after running my code (it works for a little bit then it crashes) :
Exception in thread "Thread-4" java.lang.NullPointerException
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:339)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.scene.control.TextInputControl$TextProperty.fireValueChangedEvent(TextInputControl.java:1116)
at javafx.scene.control.TextInputControl$TextProperty.markInvalid(TextInputControl.java:1120)
at javafx.scene.control.TextInputControl$TextProperty.set(TextInputControl.java:1056)
at javafx.scene.control.TextInputControl.setText(TextInputControl.java:279)
at application.MainWindowController.run(MainWindowController.java:208)
Please Help and thanks in advance
You can use TimeLine And KeyFrames. Just replace showTime() with your own code.
and do not extend thread.
public class FXMLTimeController implements Initializable {
#FXML
private TextField txtTime;
//timeline
private Timeline timeline;
private void showTime() {
txtTime.setText((new Date()).toString());
}
#Override
public void initialize(URL url, ResourceBundle rb) {
timeline = new Timeline();
timeline.setCycleCount(Timeline.INDEFINITE);
timeline.setAutoReverse(false);
timeline.getKeyFrames().add(
new KeyFrame(Duration.seconds(1),
new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
showTime();
}
}));
timeline.play();
}
}
I would suggest calling Platform.runLater(Runnable runnable) in initialize() while passing in JavaFX's TextField fields, instead of making your controller extend Thread, since JavaFX uses the controller for itself.
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
Platform.runLater(
new someThread(dayText, monthText, yearText,
hoursText, minutesText, secondsText));
}
public class someThread implements Runnable {
public someThread(TextField... textFields) {
// Create local variables
}
#Override
public void run() {
// while (true) loop goes here
}
}
You could also use this to pass in your controller as a parameter for someThread and make your TextFields public so they can be accessed by someThread.

Pointer exception in JavaFx when trying to recplace scene content

I just started Java and getting some GUI with Fx but I get an null pointer exception when trying to replace my scenecontent.
In the main the Login.fxml is loaded without any problem but when I click to the button for switching to another fxml I get the error.
The main:
package application;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.fxml.JavaFXBuilderFactory;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Main extends Application {
private Stage stage;
#Override
public void start(Stage primaryStage) {
Parent root;
try {
root = FXMLLoader.load(getClass().getResource("Login.fxml"));
} catch (IOException e) {
e.printStackTrace();
return;
}
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void gotoMainView() {
try {
MainViewController profile = (MainViewController) replaceSceneContent("MainView.fxml");
profile.setApp(this);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
void Userlogin()
{
gotoMainView();
}
private void gotoLogin() {
try {
LoginController login = (LoginController) replaceSceneContent("Login.fxml");
login.setApp(this);
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
private Initializable replaceSceneContent(String fxml) throws Exception {
FXMLLoader loader = new FXMLLoader();
InputStream in = Main.class.getResourceAsStream(fxml);
loader.setBuilderFactory(new JavaFXBuilderFactory());
loader.setLocation(Main.class.getResource(fxml));
AnchorPane page;
try {
page = (AnchorPane) loader.load(in);
} finally {
in.close();
}
Scene scene = new Scene(page, 800, 600);
stage.setScene(scene);
stage.sizeToScene();
return (Initializable) loader.getController();
}
}
The Logincontroller class:
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
public class LoginController extends AnchorPane implements Initializable {
#FXML
static private Button btntext;
#FXML
static private TextField loginusr;
#FXML
static private PasswordField loginpwd;
private Main application;
public void setApp(Main application){
this.application = application;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
btntext.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
System.out.println(loginusr.getText());
System.out.println(loginpwd.getText());
application.Userlogin();
}
});
}
The error occurs at:
application.Userlogin();
Many thanks in advance
The initialize() method is called as soon as the FXML is loaded. Have a look here
Your initialize() is called before setApp(Main application). At this point of time, the application object has not been initialized and is null !
This means the initialize() method is called at
MainViewController profile = (MainViewController) replaceSceneContent("MainView.fxml");
whereas application object which is used inside the initialize() is instantiated after this line, when you are using
profile.setApp(this);
So when you are trying the code application.Userlogin(); inside initalize(), at the time of execution, application is null !

Categories