I'm having an issue where I can't seem to return values from a new form in javafx using fxml.
I'm trying to have a main form which has 4 functions in relation to the game of connect 4 Start Game, View Players, View Games, View Player Games
When I start the program the main menu pops up, I then want to click on the "Start Game" button. After that opens it will prompt to enter user 1's information. It then pops up a new form about player information.
The problem i'm having is that after clicking the accept button the variables in the class become null I have tried accessing from the main menu class via instance get methods and also returning back to the main class.
After the ShowAndWait line the variables seem to be nulled out. Howe can i retrieve the variable information (in c# fashion) after the winodow
package Homework_5;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.ArrayList;
public class Connect4Window extends Application {
ArrayList<Connect4Game> games = new ArrayList<>();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("FXML_Files/MainMenu.fxml"));
primaryStage.setTitle("Connect 4");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
MainMenu class
package Homework_5.FXML_Java_Classes;
import Homework_5.DataClasses.PersonData;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
public class MainMenu {
@FXML
private Button btnViewGames;
@FXML
private Button btnViewPlayers;
@FXML
private Button btnStartGame;
@FXML
private Button btnViewPlayerGames;
@FXML
void startGame(ActionEvent event) {
Alert alert = new Alert(Alert.AlertType.NONE, "Please enter player 1 info");
alert.setHeaderText(null);
alert.setTitle("Player 1 info");
alert.showAndWait();
PlayerInfo playerInfo = new PlayerInfo();
playerInfo.Show();
System.out.println(playerInfo.getTxtName()); //Shows null
System.out.println(playerInfo.isInfoAccepted()); //Shows null
System.out.println(playerInfo.getChkComputer()); //Shows null
System.out.println(playerInfo.getColor()); //Shows null
}
@FXML
void viewPlayers(ActionEvent event) {
System.out.println("view players");
}
@FXML
void viewPlayerGames(ActionEvent event) {
System.out.println("view playergames");
}
@FXML
void viewGames(ActionEvent event) {
System.out.println("view games");
}
}
Player Info Class
package Homework_5.FXML_Java_Classes;
import Homework_5.DataClasses.PersonData;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class PlayerInfo {
@FXML
private Button btnAccept;
@FXML
private ColorPicker colorColorPicker;
@FXML
private CheckBox chkComputer;
@FXML
private TextField txtName;
@FXML
private Button btnClear;
private boolean infoAccepted = false;
public PlayerInfo(){
}
public PersonData Show()
{
try{
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../FXML_Files/PlayerInfo.fxml"));
Parent root1 = fxmlLoader.load();
Stage stage = new Stage();
stage.initModality(Modality.WINDOW_MODAL);
stage.setTitle("Enter Player Information");
stage.setScene(new Scene(root1));
stage.showAndWait();
return new PersonData(txtName.getText(), colorColorPicker.getValue(), chkComputer.isSelected());
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
@FXML
void Accept(ActionEvent event) {
if (txtName.getText().isEmpty()) {
Alert alert = new Alert(Alert.AlertType.WARNING, "The name field is blank!\n\nPlease enter a name.");
alert.setHeaderText(null);
alert.setTitle("Name Blank");
alert.showAndWait();
} else {
infoAccepted = true;
Stage stage = (Stage) btnAccept.getScene().getWindow();
stage.close();
}
}
@FXML
void Clear(ActionEvent event) {
txtName.clear();
colorColorPicker.setValue(Color.WHITE);
chkComputer.setSelected(false);
}
public Color getColor() {
return colorColorPicker.getValue();
}
public boolean getChkComputer() {
return chkComputer.isSelected();
}
public String getTxtName() {
return txtName.getText();
}
public boolean isInfoAccepted() {
return infoAccepted;
}
}
MainMenu fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="81.0" prefWidth="442.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Homework_5.FXML_Java_Classes.MainMenu">
<children>
<Button fx:id="btnStartGame" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onAction="#startGame" prefHeight="55.0" prefWidth="86.0" text="Start Game" />
<Button fx:id="btnViewPlayers" layoutX="110.0" layoutY="14.0" mnemonicParsing="false" onAction="#viewPlayers" prefHeight="55.0" prefWidth="86.0" text="View Players" />
<Button fx:id="btnViewPlayerGames" layoutX="302.0" layoutY="14.0" mnemonicParsing="false" onAction="#viewPlayerGames" prefHeight="55.0" prefWidth="127.0" text="View Player Games" />
<Button fx:id="btnViewGames" layoutX="206.0" layoutY="14.0" mnemonicParsing="false" onAction="#viewGames" prefHeight="55.0" prefWidth="86.0" text="View Games" />
</children>
</AnchorPane>
Player Info fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane prefHeight="201.0" prefWidth="213.0" rotate="-0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Homework_5.FXML_Java_Classes.PlayerInfo">
<children>
<Button fx:id="btnAccept" cancelButton="true" layoutX="14.0" layoutY="165.0" mnemonicParsing="false" onAction="#Accept" text="Accept" />
<Button fx:id="btnClear" layoutX="156.0" layoutY="165.0" mnemonicParsing="false" onAction="#Clear" text="Clear" />
<CheckBox fx:id="chkComputer" layoutX="57.0" layoutY="126.0" mnemonicParsing="false" text="Computer" />
<ColorPicker fx:id="colorColorPicker" layoutX="57.0" layoutY="81.0" />
<TextField fx:id="txtName" layoutX="57.0" layoutY="41.0" />
<Label contentDisplay="CENTER" layoutX="14.0" layoutY="14.0" text="Please Enter User Information below" />
<Label layoutX="14.0" layoutY="45.0" text="Name:" />
<Label layoutX="14.0" layoutY="85.0" text="Color:" />
</children>
</AnchorPane>
The PersonInfo
instance you call Show()
on is not the one used with PlayerInfo.fxml
. FXMLLoader
creates a new instance of the controller class, if the fx:controller
attribute is provided. To access this instance, use FXMLLoader
's getController
method after calling load()
.
You could e.g. create a static
method loading the and use it to create the controller:
public class PlayerInfo {
@FXML
private Parent root1;
public static PlayerInfo create() throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../FXML_Files/PlayerInfo.fxml"));
fxmlLoader.load();
return fxmlLoader.getController();
}
public PersonData Show() {
Stage stage = new Stage();
stage.initModality(Modality.WINDOW_MODAL);
stage.setTitle("Enter Player Information");
stage.setScene(new Scene(root1));
stage.showAndWait();
return new PersonData(txtName.getText(), colorColorPicker.getValue(), chkComputer.isSelected());
}
...
}
<AnchorPane fx:id="root1" prefHeight="201.0" prefWidth="213.0" rotate="-0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Homework_5.FXML_Java_Classes.PlayerInfo">
...
PlayerInfo playerInfo = PlayerInfo.create();
playerInfo.Show();
Alternatively you could use <fx:root>
and load the fxml from the constructor of the "controller", see the custom component approach in Introduction to FXML