Create and bind DoubleProperty in user control with FXML - javafx

I create a user control that represents a NumPad keyboard. The width and height of the individual buttons I want to be realized as DoubleProperty so it can be configured later.
The problem I'm encountering is that I can not bind the property to the prefWidth and prefHeight of the GridPane columns and rows in the FXML file. The only way I manage to do this is by making the connection in the control controller. But I want to avoid it if possible.
This is the problematic FXML file.
<fx:root type="javafx.scene.layout.GridPane" xmlns="http://javafx.com/javafx/" xmlns:fx="http://javafx.com/fxml/1">
<fx:define>
<SimpleDoubleProperty fx:id="size">
<value>
<Double fx:value="50"/>
</value>
</SimpleDoubleProperty>
</fx:define>
<gridLinesVisible>false</gridLinesVisible>
<hgap>5</hgap>
<vgap>5</vgap>
<Button text="C" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="0" GridPane.rowIndex="0" focusTraversable="false"/>
<Button text="Backspace" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="2" GridPane.rowIndex="0" GridPane.columnSpan="2" focusTraversable="false"/>
<Button text="7" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="0" GridPane.rowIndex="1" focusTraversable="false"/>
<Button text="8" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="1" GridPane.rowIndex="1" focusTraversable="false"/>
<Button text="9" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="2" GridPane.rowIndex="1" focusTraversable="false"/>
<Button text="4" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="0" GridPane.rowIndex="2" focusTraversable="false"/>
<Button text="5" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="1" GridPane.rowIndex="2" focusTraversable="false"/>
<Button text="6" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="2" GridPane.rowIndex="2" focusTraversable="false"/>
<Button text="1" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="0" GridPane.rowIndex="3" focusTraversable="false"/>
<Button text="2" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="1" GridPane.rowIndex="3" focusTraversable="false"/>
<Button text="3" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="2" GridPane.rowIndex="3" focusTraversable="false"/>
<Button text="0" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="0" GridPane.rowIndex="4" GridPane.columnSpan="2" focusTraversable="false"/>
<Button text="." maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="2" GridPane.rowIndex="4" focusTraversable="false"/>
<Button text="E" onAction="#f" maxWidth="Infinity" maxHeight="Infinity" GridPane.columnIndex="3" GridPane.rowIndex="2" GridPane.rowSpan="3" focusTraversable="false"/>
<columnConstraints>
<ColumnConstraints fx:id="col1" prefWidth="${size.value}"/>
<ColumnConstraints fx:id="col2" prefWidth="${size.value}"/>
<ColumnConstraints fx:id="col3" prefWidth="${size.value}"/>
<ColumnConstraints fx:id="col4" prefWidth="${size.value}"/>
</columnConstraints>
<rowConstraints>
<RowConstraints fx:id="row1" prefHeight="${size.value}"/>
<RowConstraints fx:id="row2" prefHeight="${size.value}"/>
<RowConstraints fx:id="row3" prefHeight="${size.value}"/>
<RowConstraints fx:id="row4" prefHeight="${size.value}"/>
<RowConstraints fx:id="row5" prefHeight="${size.value}"/>
</rowConstraints>
</fx:root>
${size.value} initializes the control correctly, but there is no bind between size and ColumnConstraints#prefWidthProperty / RowConstraints#prefHeightProperty.
If I do the binding manually, everything works. But as I said, I want to avoid it if possible.
#FXML
private void initialize() {
col1.prefWidthProperty().bind(size);
// ...
row1.prefHeightProperty().bind(size);
// ...
}
if I use ${size} I get NumberFormatException: For input string: "DoubleProperty [value: 50.0]"

Direct access to properties does not seem possible via expression binding.
If you provide access to the property through the controller however, you could use ${controller.size} instead to create the binding:
#FXML
private DoubleProperty size;
public final double getSize() {
return size.get();
}
public final void setSize(double value) {
size.set(value);
}
public final DoubleProperty sizeProperty() {
return size;
}
...
<columnConstraints>
<ColumnConstraints fx:id="col1" prefWidth="${controller.size}"/>
<ColumnConstraints fx:id="col2" prefWidth="${controller.size}"/>
<ColumnConstraints fx:id="col3" prefWidth="${controller.size}"/>
<ColumnConstraints fx:id="col4" prefWidth="${controller.size}"/>
</columnConstraints>
<rowConstraints>
<RowConstraints fx:id="row1" prefHeight="${controller.size}"/>
<RowConstraints fx:id="row2" prefHeight="${controller.size}"/>
<RowConstraints fx:id="row3" prefHeight="${controller.size}"/>
<RowConstraints fx:id="row4" prefHeight="${controller.size}"/>
<RowConstraints fx:id="row5" prefHeight="${controller.size}"/>
</rowConstraints>
...

Related

My FXML page is not loading, I cannot figure out why

I am having problems figuring out why a page I am trying to load with my JFX FXML loader the page does not load..
With regards to my my FXML load class, my java code complies, but when I execute the code the "More Details page does not load and display when I click on the "More Details" button...here is the code segment that loads the "More Details" page...
// Now set up the stage and place the "post_details_update" on it.
Stage unilink_home_stage = (Stage) btnl_posting_more_details.getScene().getWindow();
unilink_home_stage.close();
// This closes the Login dialog
// now call the post_details_update.fxml
try {
//Parent post_details = FXMLLoader.load( getClass().getResource("/unilink_home/post_details/post_details_update.fxml"));
Parent post_details = FXMLLoader.load( getClass().getResource("/view/unilink_home/post_details/post_details_update.fxml"));
// Note: the path is not relative to the package that this file is in
// but the CLASSPATH from the src/
Stage post_details_stage = new Stage();
post_details_stage.setTitle("Welcome to UniLink");
post_details_stage.setScene(new Scene(post_details));
post_details_stage.show();
} //close the try block
catch(Exception e)
{
//System.out.print(e);
//e.printStackTrace();
System.out.println( e.getMessage() );
}// close the catch block
And the folder structure is...
and the FXML page is.... "post_details_update.fxml":
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.ToolBar?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<AnchorPane
fx:id="post_details"
xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/11.0.1"
fx:controller="controller/unilink_home/post/details/unilink_home_post_detailsController"
>
<children>
<VBox prefHeight="401.0" prefWidth="850.0">
<children>
<ToolBar prefHeight="40.0" prefWidth="850.0">
<items>
<Button mnemonicParsing="false" text="Back to Main Window" />
<Label text="Review Post Details">
<padding>
<Insets left="250.0" />
</padding>
</Label>
</items>
</ToolBar>
<GridPane prefHeight="183.0" prefWidth="849.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="474.0" minWidth="10.0" prefWidth="215.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="541.0" minWidth="10.0" prefWidth="101.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="541.0" minWidth="10.0" prefWidth="534.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="144.0" minHeight="10.0" prefHeight="144.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="71.0" minHeight="10.0" prefHeight="39.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<ImageView fitHeight="135.0" fitWidth="222.0" pickOnBounds="true" preserveRatio="true">
<GridPane.margin>
<Insets left="50.0" />
</GridPane.margin>
<image>
<Image url="#../../../../images/under_construction.png" />
</image>
</ImageView>
<GridPane prefHeight="131.0" prefWidth="277.0" GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Post ID:" />
<Label layoutX="10.0" layoutY="25.0" text="Title:" GridPane.rowIndex="1" />
<Label layoutX="10.0" layoutY="72.0" text="Description:" GridPane.rowIndex="2" />
<Label layoutX="10.0" layoutY="89.0" text="Creator:" GridPane.rowIndex="3" />
<Label layoutX="10.0" layoutY="99.0" text="Date Created:" GridPane.rowIndex="4" />
<Label layoutX="10.0" layoutY="105.0" text="Status:" GridPane.rowIndex="5" />
</children>
</GridPane>
<GridPane layoutX="225.0" layoutY="10.0" prefHeight="131.0" prefWidth="277.0" GridPane.columnIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="47.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="46.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="46.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
<Button mnemonicParsing="false" text="Upload Image" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="70.0" />
</GridPane.margin>
</Button>
<Button mnemonicParsing="false" text="Close Post" GridPane.columnIndex="2" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="20.0" />
</GridPane.margin>
</Button>
<Button mnemonicParsing="false" text="Delete Post" GridPane.columnIndex="2" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="180.0" />
</GridPane.margin>
</Button>
<Button mnemonicParsing="false" text="Save" GridPane.columnIndex="2" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="350.0" />
</GridPane.margin>
</Button>
</children>
</GridPane>
<ListView prefHeight="200.0" prefWidth="200.0" />
</children>
</VBox>
</children>
</AnchorPane>
And the "unilink_home_post_detailsController.java" is just a shell at this stage...
package controller.unilink_home.post.details;
import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;
import model.connectionTest;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ChoiceBox;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
//import javafx.event.Event;
//Import the classes for database query
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import model.table_setup_view_postings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.Initializable;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import java.net.URL;
import java.util.ResourceBundle;
import model.posting;
public class unilink_home_post_detailsController implements Initializable
{
//database connection related variables,
private String query;
//This is the SQL query string
PreparedStatement ps;
//PreparedStatement ps2;
// This is the prepared statement for the SQL query
private Connection db_connect;
// this is the database connection string for SQL query results
final String DB_NAME = "testDB";
// This is the database name
#FXML // fx:id="post_details"
private AnchorPane post_details; // Value injected by FXMLLoader
//===================================================================================================================
/*
* This method is the class constructor and sets up the controller.
*/
public void unilink_home_post_detailsController()
{
}// close public void unilink_home_post_detailsController()
//===================================================================================================================
/*
* This method will initialiise the UI
*/
//#FXML
#Override
public void initialize(URL location, ResourceBundle resources)
{
}// close public void initialize(URL location, ResourceBundle resources)
}// close public class unilink_home_post_detailsController
With this:
1. The code will compile.
2. When I click the button "More Details"... nothing happens and I am also challenged how I can debug it because in Eclipse with Java JFX the step in/over buttons are greyed out, and it is not showing the variables so I can see the state of these vraibles?
Can anyone help, as I am somewhat new to JFX, and I have read that the FXML loader can be finnicky...
Sincerely.
I found the problem was in the path that I used to point to the controller... somehow I had "/" instead of "." when I made the change it worked. Thank you to those whoresponded.

TextField textProperty Listener across embedded scenes JavaFX

This may be a little convoluted but please bear with me.
I have 3 scenes built using SceneBuilder. The first ("Main") I am using as the parent scene. This scene contains 1 AnchorPane which holds a TabPane and a ToolBar which holds 3 Buttons ("Previous", "Next" and "Close").
The second scene ("PersonaDetails") contains an AnchorPane, a GridPane a number of Textflow (which I am using as field labels) several TextField and DatePicker. This whole scene is embedded into one of the tabs on the TabPane on the first scene ("Main").
The third scene ("Address") is very similar to the second where it contains an AnchorPane, a GridPane a number of Textflow (which I am using as field labels) several TextField and ComboBox. This whole scene is embedded into the other tab on the TabPane on the first scene ("Main").
(I have included the FXML script for each below)
The application will later include additional scenes on additional tab on the TabPane on the first scene ("Main"). This application will form part of larger application and is meant to be a kind of wizard that allows new clients to be registered.
Furthermore, each FXML file and its Controller are in separate packages.
This issue I am having is that I need to add .textProperty() listeners on several of the Textfield so that I can enable, or disable the "Next" Button on the first, or parent, scene ("Main").
I have tried the following code in the MainController class, but it does not work, although it does not generate any errors.
package com.yas.registrationwizard.main;
import com.yas.registrationwizard.personaldetails.PersonalDetailsController;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
#FXML AnchorPane apMain;
#FXML ToolBar tbMain;
#FXML TabPane tpMain;
#FXML Button btnPrevious;
#FXML Button btnNext;
#FXML Button btnClose;
#Override
public void initialize(URL location, ResourceBundle resources) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../personaldetails/PersonalDetails.fxml"));
try {
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
PersonalDetailsController personalDetailsController = fxmlLoader.getController();
personalDetailsController.tfFirstName.textProperty().addListener((obs, oldVal, newVal) -> {
if(newVal.equals("")) {
btnNext.setDisable(true);
} else {
btnNext.setDisable(false);
}
});
}
}
The FXML scripts are as follows:
Main
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="apMain" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.main.MainController">
<children>
<ToolBar fx:id="tbMain" layoutX="259.0" layoutY="339.0" prefHeight="40.0" prefWidth="200.0" AnchorPane.bottomAnchor="5.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="355.0">
<items>
<Pane prefHeight="30.0" prefWidth="370.0" />
<Button fx:id="btnPrevious" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Previous" />
<Button fx:id="btnNext" layoutX="10.0" layoutY="13.0" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Next" />
<Button fx:id="btnClose" layoutX="66.0" layoutY="13.0" maxHeight="25.0" maxWidth="65.0" minHeight="25.0" minWidth="65.0" mnemonicParsing="false" prefHeight="25.0" prefWidth="65.0" text="Close" />
</items>
</ToolBar>
<TabPane fx:id="tpMain" layoutX="14.0" layoutY="14.0" prefHeight="335.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="5.0" AnchorPane.topAnchor="5.0">
<tabs>
<Tab fx:id="tabPersonalDetails" text="Personal Deatils">
<content>
<fx:include fx:id="apPersonalDetails" source="../personaldetails/PersonalDetails.fxml" />
</content></Tab>
<Tab fx:id="tabAddress" text="Address">
<content>
<fx:include fx:id="apAddress" source="../address/Address.fxml" />
</content></Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
Address
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="apAddress" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="325.0" prefWidth="590.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.address.AddressController">
<children>
<GridPane fx:id="gpAddress" layoutX="195.0" layoutY="103.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="103.0" minWidth="3.0" prefWidth="82.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="219.0" minWidth="10.0" prefWidth="155.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="422.0" minWidth="10.0" prefWidth="274.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="93.0" minWidth="0.0" prefWidth="78.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="295.0" text="House Name / Number:" GridPane.columnIndex="1" GridPane.rowIndex="2">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin></Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="246.0" text="Address Line 1:" GridPane.columnIndex="1" GridPane.rowIndex="3">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin></Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="239.0" text="Address Line 2:" GridPane.columnIndex="1" GridPane.rowIndex="4">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin></Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Town / City:" GridPane.columnIndex="1" GridPane.rowIndex="5">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin></Label>
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="237.0" text="Region / County:" GridPane.columnIndex="1" GridPane.rowIndex="6">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin></Label>
<TextField fx:id="tfHseNameNum" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<TextField fx:id="tfAddLine1" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<TextField fx:id="tfAddLine2" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<TextField fx:id="tfTownCity" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<TextField fx:id="tfRegionCounty" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Postcode:" GridPane.columnIndex="1" GridPane.rowIndex="7">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin>
</Label>
<TextField fx:id="tfPostcode" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="234.0" text="Country:" GridPane.columnIndex="1" GridPane.rowIndex="8">
<GridPane.margin>
<Insets right="10.0" />
</GridPane.margin>
</Label>
<ComboBox fx:id="cboCountry" prefHeight="25.0" prefWidth="294.0" GridPane.columnIndex="2" GridPane.rowIndex="8" />
</children>
</GridPane>
</children>
</AnchorPane>
PersonDetails
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="apPersonalDetails" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="325.0" prefWidth="590.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.yas.registrationwizard.personaldetails.PersonalDetailsController">
<children>
<GridPane fx:id="gpPersonalDetails" layoutX="195.0" layoutY="103.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="37.0" prefWidth="37.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="236.0" minWidth="10.0" prefWidth="236.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="422.0" minWidth="10.0" prefWidth="277.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="80.0" minWidth="38.0" prefWidth="41.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<TextField fx:id="tfFirstName" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<TextField fx:id="tfMidNameInit" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<TextField fx:id="tfLastName" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<DatePicker fx:id="dpDoB" prefHeight="25.0" prefWidth="365.0" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<TextField fx:id="tfNatInsNum" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<TextFlow fx:id="tflFirstName" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="2">
<GridPane.margin>
<Insets right="10.0" top="10.0" />
</GridPane.margin></TextFlow>
<TextFlow fx:id="tflLastName" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="4">
<padding>
<Insets right="10.0" top="10.0" />
</padding>
</TextFlow>
<TextFlow fx:id="tflDoB" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="5">
<padding>
<Insets right="10.0" top="10.0" />
</padding>
</TextFlow>
<TextFlow fx:id="tflNatInsNum" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="6">
<padding>
<Insets right="10.0" top="10.0" />
</padding>
</TextFlow>
<TextFlow fx:id="tflMidNameInit" prefHeight="16.0" prefWidth="162.0" style="-fx-text-alignment: right;" styleClass="txtFlow" GridPane.columnIndex="1" GridPane.rowIndex="3">
<padding>
<Insets right="10.0" top="10.0" />
</padding>
</TextFlow>
</children>
</GridPane>
</children>
</AnchorPane>
The folder structure for the project is shown in the image below:
Firstly, I am bit confused with the wording "scene" in the question. I believe what you mentioned in the question is about handling the nodes, because all the fxmls are handled in the same Scene/Stage.
Anyway, the main problem of the issue lies in the MainController initialize method. You are loading a new instance of PersonalDetailsController and working on it, instead of working on the controller that is actually binded to MainController.
When including fxmls in an fxml, the sub fxml's controller will be already injected to the main fxml controller. So I believe changing your MainController code as below should work as expected.
Update: Sorry for a bit misleading info. The correct thing is, you need to inject the controller with a certain naming convention. If you are including an fxml using fx:include, to get the controller you need to inject with a naming convention <fxid>Controller and <fxid> for getting the node reference.
So considering your example, for the given fx:include line:
<fx:include fx:id="apPersonalDetails" source="../personaldetails/PersonalDetails.fxml" />
your code in MainController should be:
// For controller reference
#FXML PersonalDetailsController apPersonalDetailsController;
// For Node reference
#FXML AnchorPane apPersonalDetails;
So the updated code will be as below:
import com.yas.registrationwizard.personaldetails.PersonalDetailsController;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
#FXML AnchorPane apMain;
#FXML ToolBar tbMain;
#FXML TabPane tpMain;
#FXML Button btnPrevious;
#FXML Button btnNext;
#FXML Button btnClose;
#FXML PersonalDetailsController apPersonalDetailsController;
#Override
public void initialize(URL location, ResourceBundle resources) {
apPersonalDetailsController.tfFirstName.textProperty().addListener((obs, oldVal, newVal) -> {
if(newVal.equals("")) {
btnNext.setDisable(true);
} else {
btnNext.setDisable(false);
}
});
}
}

How to create Javafx save, read information from text file and letting user to edit their information

How to create JavaFx RegisterGUI save user information(Username,password,name,email,phone number,address) and load into UserProfile GUI that allow the user to edit their profile information after login with their username and password? Hope you guys can help me with the problems.
UserGUI:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Text?>
<GridPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.GUIButton">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button id="btnEdit" fx:id="btnEdit" mnemonicParsing="false" onAction="#setOnAction" text="Edit Profile" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Button id="btnSave" fx:id="btnSave" mnemonicParsing="false" onAction="#setOnAction" prefHeight="26.0" prefWidth="73.0" text="Save" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<Button id="btnCancel" fx:id="btnCancel" mnemonicParsing="false" onAction="#setOnAction" prefHeight="26.0" prefWidth="66.0" text="Cancel" GridPane.columnIndex="3" GridPane.rowIndex="9" />
<Text id="txtName" strokeType="OUTSIDE" strokeWidth="0.0" text="Name" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Text id="txtPhoneNumber" strokeType="OUTSIDE" strokeWidth="0.0" text="Phone Number" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Text id="txtEmail" strokeType="OUTSIDE" strokeWidth="0.0" text="Email" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Text id="txtAddress" strokeType="OUTSIDE" strokeWidth="0.0" text="Address" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<TextField id="txtfName" onAction="#setOnAction" prefHeight="26.0" prefWidth="203.0" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<TextField id="txtfPhoneNumber" onAction="#setOnAction" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<TextField id="txtfEmail" onAction="#setOnAction" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<TextArea id="txtaAddress" onDragDetected="#setOnAction" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<ImageView id="imgUser" fitHeight="150.0" fitWidth="200.0" pickOnBounds="true" preserveRatio="true" GridPane.columnIndex="4" GridPane.rowIndex="2" />
</children>
</GridPane>
RegisterGUI :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Text?>
<GridPane id="RegisterGUI" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/10.0.1" fx:controller="application.RegisterButton">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="193.5999755859375" minWidth="10.0" prefWidth="151.20003662109374" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="193.5999755859375" minWidth="10.0" prefWidth="151.20003662109374" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="447.9999633789063" minWidth="10.0" prefWidth="447.9999633789063" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Email" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Username" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Name" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="IC Number" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Phone Number" GridPane.columnIndex="1" GridPane.rowIndex="6" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Address" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<TextField id="txtfEmail" fx:id="txtfEmail" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<TextField id="txtfUsername" fx:id="txtfUsername" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<TextField id="txtfName" fx:id="txtfName" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<TextField id="txtfIC" fx:id="txtfIC" GridPane.columnIndex="2" GridPane.rowIndex="5" />
<TextField id="txtfPhone" fx:id="txtfPhone" GridPane.columnIndex="2" GridPane.rowIndex="6" />
<TextArea id="txtaAddress" fx:id="txtaAddress" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="2" GridPane.rowIndex="7" />
<Button id="btnRegister" fx:id="btnRegister" mnemonicParsing="false" onAction="#OnRegister" text="Register" GridPane.columnIndex="2" GridPane.rowIndex="9" />
<Button id="btnExit" fx:id="btnExit" mnemonicParsing="false" onAction="#OnExit" prefHeight="26.0" prefWidth="56.0" text="Exit" GridPane.columnIndex="1" GridPane.rowIndex="9" />
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Password" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<TextField id="txtfPassword" fx:id="txtfPassword" GridPane.columnIndex="2" GridPane.rowIndex="3" />
</children>
</GridPane>
Ok build a small login, Signup, and Edit app for you, You can modify it as u like
So we have 4 class files. and 2 FXML files and Textfile
Luncher.java
package loginApplication;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Luncher extends Application{
public static Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
Parent root = FXMLLoader.load(getClass().getResource("Login.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
LoginController.java
package loginApplication;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
public class LoginController
{
#FXML
private TextField email_textfield;
#FXML
private PasswordField password_textfield;
#FXML
private Label error_lab;
#FXML
public void signupButton(ActionEvent event) {
openWindow();
}
#FXML
public void loginButton(ActionEvent event) throws IOException
{
//Path to text file
Path path = Paths.get("TextFiles/data.txt");
//Counts number of line in text file
long count = Files.lines(path).count();
/// read each line
for (int i = 0; i < count; i++)
{
String line = Files.readAllLines(path).get(i);
if(!line.trim().equals(""))
{
//According to format Name, Email, Password, Age, Gender
String[] profile = line.split(",");
String name = profile[0];
String email = profile[1];
String password = profile[2];
String age = profile[3];
String gender = profile[4];
String contact = profile[5];
//Email Matched!
if(email.trim().equals(email_textfield.getText()))
{ //Note trim() method remove space from front and behind of string if there is any
//Now checking if password match
if(password.trim().equals(password_textfield.getText()))
{
Alert msg = new Alert(AlertType.CONFIRMATION);
msg.setTitle(email_textfield.getText());
msg.setContentText("Email and password matched");
msg.showAndWait();
//Store values
Storage.setName(name);
Storage.setEmail(email);
Storage.setAge(age);
Storage.setGender(gender);
Storage.setContact(contact);
Storage.setPassword(password);
//open login window
openWindow();
break; //Email match and pass match, Close loop
}
}
}
}
if(Storage.getEmail() == null) {
System.out.println("No such email");
Alert msg = new Alert(AlertType.ERROR);
msg.setTitle(email_textfield.getText());
msg.setContentText("No such Email : " +email_textfield.getText());
msg.showAndWait();
} else if (Storage.getPassword() == null){
System.out.println("No such email");
Alert msg = new Alert(AlertType.ERROR);
msg.setTitle(email_textfield.getText());
msg.setContentText("Wrong password");
msg.showAndWait();
}
}
private void openWindow()
{
System.out.println("Profile open");
try {
Parent root = FXMLLoader.load(getClass().getResource("Profile.fxml"));
Luncher.stage.setScene(new Scene(root));
} catch (IOException e) {
e.printStackTrace();
}
}
}
ProfileController.java
package loginApplication;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
public class ProfileController implements Initializable{
#FXML
private TextField name;
#FXML
private TextField email;
#FXML
private TextField gender;
#FXML
private TextField contact;
#FXML
private TextField age;
#FXML
private PasswordField password;
#Override
public void initialize(URL location, ResourceBundle resources) {
name.setText(Storage.getName());
age.setText(Storage.getAge());
gender.setText(Storage.getGender());
email.setText(Storage.getEmail());
contact.setText(Storage.getContact());
password.setText(Storage.getPassword());
//Open windows for sign up if nall else do this
if(Storage.getEmail() !=null)
{
//Disable everything
name.setDisable(true);
age.setDisable(true);
gender.setDisable(true);
email.setDisable(true);
contact.setDisable(true);
password.setDisable(true);
}
}
#FXML
private Button save;
#FXML
private Button edit;
#FXML
void editButton(ActionEvent event)
{
System.out.println("edit button");
//Active everything
name.setDisable(false);
age.setDisable(false);
gender.setDisable(false);
email.setDisable(false);
contact.setDisable(false);
password.setDisable(false);
}
#FXML
void saveButton(ActionEvent event) {
//Disable everything
name.setDisable(true);
age.setDisable(true);
gender.setDisable(true);
email.setDisable(true);
contact.setDisable(true);
password.setDisable(true);
removeLine();
addLine();
}
private void addLine() {
String line = name.getText() +"," +email.getText() +"," +password.getText() +"," +age.getText() +"," +gender.getText()+"," +contact.getText();
FileWriter file_writer;
try {
file_writer = new FileWriter("TextFiles/data.txt",true);
BufferedWriter buffered_Writer = new BufferedWriter(file_writer);
buffered_Writer.write(line);
buffered_Writer.flush();
buffered_Writer.close();
} catch (IOException e) {
System.out.println("Add line failed!!" +e);
}
}
private void removeLine() {
try
{
BufferedReader file = new BufferedReader(new FileReader("TextFiles/data.txt"));
String line;
String input = "";
while ((line = file.readLine()) != null)
{
//System.out.println(line);
if (line.contains(Storage.getEmail()))
{
line = "";
System.out.println("Line deleted.");
}
input += line + '\n';
}
FileOutputStream File = new FileOutputStream("TextFiles/data.txt");
File.write(input.getBytes());
file.close();
File.close();
}
catch (Exception e)
{
System.out.println("Problem reading file.");
}
}
}
Storage.java
package loginApplication;
public class Storage {
private static String Name;
private static String Age;
private static String Gender;
private static String Email;
private static String Contact;
private static String password;
// This is how u should do it but u can also make field public and use them directly
// for example -> 'Public static String Name' then use it as 'Storage.name'
public static String getName() {
return Name;
}
public static void setName(String name) {
Name = name;
}
public static String getAge() {
return Age;
}
public static void setAge(String age) {
Age = age;
}
public static String getGender() {
return Gender;
}
public static void setGender(String gender) {
Gender = gender;
}
public static String getEmail() {
return Email;
}
public static void setEmail(String email) {
Email = email;
}
public static String getContact() {
return Contact;
}
public static void setContact(String contact) {
Contact = contact;
}
public static String getPassword() {
return password;
}
public static void setPassword(String password) {
Storage.password = password;
}
}
Login.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" onDragDetected="#loginButton" prefHeight="390.0" prefWidth="304.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="loginApplication.LoginController">
<children>
<TextField fx:id="email_textfield" layoutX="38.0" layoutY="83.0" prefHeight="34.0" prefWidth="229.0" promptText="Email">
<font>
<Font size="14.0" />
</font>
</TextField>
<PasswordField fx:id="password_textfield" layoutX="38.0" layoutY="152.0" prefHeight="34.0" prefWidth="229.0" promptText="Password" />
<Button layoutX="87.0" layoutY="222.0" mnemonicParsing="false" onAction="#loginButton" prefHeight="51.0" prefWidth="131.0" text="Login" textAlignment="CENTER" textFill="#328d38">
<font>
<Font name="Courier New Bold" size="22.0" />
</font>
</Button>
<Label fx:id="error_lab" layoutX="59.0" layoutY="284.0" prefHeight="29.0" prefWidth="229.0" textFill="#ee0c0c">
<font>
<Font size="18.0" />
</font>
</Label>
<Button layoutX="110.0" layoutY="284.0" mnemonicParsing="false" onAction="#signupButton" prefHeight="29.0" prefWidth="85.0" text="Sign up" textAlignment="CENTER" textFill="#3b21e4">
<font>
<Font name="Courier New Bold" size="15.0" />
</font>
</Button>
</children>
</AnchorPane>
Profile.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.PasswordField?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="420.0" prefWidth="560.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="loginApplication.ProfileController">
<children>
<Button fx:id="edit" layoutX="202.0" layoutY="363.0" mnemonicParsing="false" onAction="#editButton" prefHeight="26.0" prefWidth="111.0" text="Edit">
<font>
<Font size="14.0" />
</font>
</Button>
<TextField fx:id="name" layoutX="202.0" layoutY="28.0" prefHeight="25.0" prefWidth="329.0" promptText="Name">
<font>
<Font size="18.0" />
</font>
</TextField>
<TextField fx:id="email" layoutX="202.0" layoutY="242.0" prefHeight="25.0" prefWidth="329.0" promptText="Email">
<font>
<Font size="18.0" />
</font>
</TextField>
<TextField fx:id="gender" layoutX="202.0" layoutY="132.0" prefHeight="25.0" prefWidth="329.0" promptText="Gender">
<font>
<Font size="18.0" />
</font>
</TextField>
<TextField fx:id="contact" layoutX="202.0" layoutY="187.0" prefHeight="25.0" prefWidth="329.0" promptText="Contact">
<font>
<Font size="18.0" />
</font>
</TextField>
<TextField fx:id="age" layoutX="202.0" layoutY="81.0" prefHeight="25.0" prefWidth="329.0" promptText="Age">
<font>
<Font size="18.0" />
</font>
</TextField>
<Button fx:id="save" layoutX="420.0" layoutY="363.0" mnemonicParsing="false" onAction="#saveButton" prefHeight="26.0" prefWidth="111.0" text="Save">
<font>
<Font size="14.0" />
</font>
</Button>
<PasswordField fx:id="password" layoutX="202.0" layoutY="297.0" prefHeight="39.0" prefWidth="329.0" promptText="Password">
<font>
<Font size="18.0" />
</font>
</PasswordField>
<Label layoutX="35.0" layoutY="34.0" text="Name">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
<Label layoutX="35.0" layoutY="88.0" text="Age">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
<Label layoutX="35.0" layoutY="139.0" text="Gender">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
<Label layoutX="35.0" layoutY="194.0" text="Contact">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
<Label layoutX="35.0" layoutY="249.0" text="Email">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
<Label layoutX="35.0" layoutY="304.0" text="Password">
<font>
<Font name="Cambria Math" size="30.0" />
</font>
</Label>
</children>
</AnchorPane>
I hope this help if something wont work or u need to know something ask it :)
I suggest you use an SQLite database and Not textfile.
But using a Text file to make a small database it's a good practice.
To do this you need to create a .txt file that's your database
In a text file, you can store information many ways for example
Name, Email, Password, Age, Gender
Jack, jack#gmail.com, mypassword123, 18, male,
Adam, adam101#gmail.com, adampas1001, 21, female,
in this way you separating data with commas
Now you have to read each line 1 by 1
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
public class TextFileReader
{
// Location / count / List
private String text_File_Location; //location
private long count;
public TextFileReader(String url)
{
this.text_File_Location = url;
lineList = new ArrayList<String>();
countLines();
initFontCodeList();
}
//Counts number of lines mean number of profiles
private void countLines()
{
try {
count = Files.lines(Paths.get(text_File_Location)).count();
} catch (IOException e1) { System.err.println("TextFileReader : Count Failed" +e1); }
}
//init List
private void initFontCodeList() {
try
{
Path path = Paths.get(text_File_Location);
for (int i = 0; i < count; i++)
{
String line = Files.readAllLines(path).get(i);
//Acording to format Name, Email, Password, Age, Gender
String[] profile = line.split(",");
String name = profile[0];
String email = profile[1];
String Password = profile[2];
String age = profile[4];
String gender = profile[5];
}
}
catch (IOException e) {System.err.println("TextFileReader : ReadFile Failed");}
}
}
Now just use a couple of logic to check if an information entered on GUI is equal textfile information
Removing profile is just deleting that line
Modifying profile is just deleting that line and creating another line
This is all the basic how to start

Accessing the column and row index of GridPane in JavaFX keeps returning null

Hi so I have tried many solutions online on how to get the Node(cell) that was clicked on in the Gridpane. The method I went with for getting the node is shown below. I have also tried iterating through all the nodes prior to this method. I have built the gridpane with scenebuilder and as you can see in the picture below the columns and row are clearly there. I am trying this solution How to get GridPane Row and Column IDs on Mouse Entered in each cell of Grid in JavaFX? however as I've mentioned above the values returned from the rows and columns are null.
#FXML
private void mouseEntered(MouseEvent e) {
Node source = (Node)e.getSource() ;
System.out.println(source);
Integer colIndex = userSelectionGrid.getColumnIndex(source);
Integer rowIndex = userSelectionGrid.getRowIndex(source);
if (colIndex == null && rowIndex == null) System.out.println("BOO");
else
System.out.printf("Mouse entered cell [%d, %d]%n", colIndex.intValue(), rowIndex.intValue());
}
FXML containing this grid
<GridPane fx:id="userSelectionGrid" onMouseClicked="#mouseEntered" prefHeight="44.0" prefWidth="563.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>
The source of the event is the Node where the handler is added, i.e. in this case the GridPane. You could add the handlers to the children of the GridPane for the source Node to be correct:
<GridPane fx:id="userSelectionGrid" prefHeight="44.0" prefWidth="563.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0" onMouseClicked="#mouseEntered">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0" onMouseClicked="#mouseEntered">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>
Note that you could also make this work with your original fxml. However there are a few things that you should consider:
null is also a valid return value for GridPane.getRowIndex and GridPane.getColumnIndex this doesn't mean the node is not the child of a GridPane, it just means the value has not been changed from the default. This has the same effect as using the value 0.
The condition
if (colIndex == null && rowIndex == null)
Is too strong to prevent a NullPointerException in the else part. This could occur e.g. if the Separator is clicked.
The target of the event is the node that is actually clicked, which could be a Node in the Label's skin. From this node you could traverse to the parent node until the parent is the GridPane to find the correct child of the GridPane.
#FXML
private void mouseEntered(MouseEvent e) {
Node target = (Node) e.getTarget();
// traverse towards root until userSelectionGrid is the parent node
if (target != userSelectionGrid) {
Node parent;
while ((parent = target.getParent()) != userSelectionGrid) {
target = parent;
}
}
Integer colIndex = userSelectionGrid.getColumnIndex(target);
Integer rowIndex = userSelectionGrid.getRowIndex(target);
if (colIndex == null || rowIndex == null) {
System.out.println("BOO");
} else {
System.out.printf("Mouse entered cell [%d, %d]%n", colIndex.intValue(), rowIndex.intValue());
}
}
Note that the Labels do not fill the full GridPane unless you set the preferred size larger than the GridPane constraints. This messes up the layout of the GridPane. A workaround would be placing Regions behind the Labels in the cells. Those can be resized with the cells without influence on the GridPane layout, which allows you to catch the event on those nodes:
<GridPane fx:id="userSelectionGrid" prefHeight="44.0" prefWidth="563.0" onMouseClicked="#mouseEntered">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" fillWidth="true" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" fillWidth="true" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="SOMETIMES" fillHeight="true" />
</rowConstraints>
<children>
<Region GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<Region GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="SAVE" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Label text="CANCEL" GridPane.columnIndex="0" GridPane.halignment="CENTER" GridPane.rowIndex="0">
<font>
<Font name="System Bold" size="13.0" />
</font>
</Label>
<Separator orientation="VERTICAL" GridPane.columnIndex="1" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</GridPane>

How to merge cells in JavaFX Scene builder?

I have a gridpane looks like a KeyBoard, and I need to merge some cells to put a "Space" button.. But I cant find any option in the settings of the gridpane which would solve my problem.. Does anyone have an idea how I could achieve it?
Setup your Grid with items in it
Create a GridPane.
Place nodes in the grid.
Select a node in the grid.
It is very, very important that a node in the grid be selected at this stage . . .
After that either:
A. Use the Menu Items
Choose Modify | GridPane
Choose any of
Increase Row Span
Decrease Row Span
Increase Column Span
Decrease Column Span
B. Use the Layout Panel
Modify the Row Span or the Column Span values.
Layout Notes
To really get something to fill up the grid and span rows or columns in the way you want, you may need to modify other layout parameters of the node or it's grid constraints in the layout panel. For example a Button won't normally grow beyond it's preferred size, so set it's max height and width to MAX_VALUE. Another example is to have a Label centered across two columns, set its Hgrow to ALWAYS and its Halignment to CENTER.
Sample Screenshot
There are menu items for setting the Row and Column Span and there are also layout text fields for the same on the far right. Unfortunately, StackOverflow compresses the pic and makes it a little blurry.
Sample FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<GridPane layoutX="116.0" layoutY="155.0">
<children>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button" GridPane.columnIndex="0" GridPane.columnSpan="2147483647" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS" />
<Label text="Label" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<Label maxWidth="-1.0" text="Label" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.halignment="CENTER" GridPane.hgrow="ALWAYS" GridPane.rowIndex="0" />
<Label text="Label" GridPane.columnIndex="0" GridPane.rowIndex="2" />
<Label text="Label" GridPane.columnIndex="1" GridPane.rowIndex="2" GridPane.rowSpan="2" />
<Label text="Label" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<Label text="Label" GridPane.columnIndex="2" GridPane.rowIndex="3" />
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="30.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="30.0" minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</children>
</AnchorPane>

Resources