I'm trying to create a gridpane which will have dynamic number of rows, according to user input. Once number of rows are known, each row will have 8 objects that are a mix of TextFields and DatePicker. I can create them but now I'm having a hard time trying to extract any data that the user will enter in them. I would possibly like to hold each textField data of one row in a seperate array, and have 8 total arrays for further use. I know there's getText(), but it isn't working on textFields that are added dynamically. What am I doing wrong here?
Following is my controller class:
private void addEntityTextFields() {
int numOfOpenTextFieldRows = Integer.parseInt(numOfEntities);
this.numOfOpenTextFieldRows = numOfOpenTextFieldRows;
EntityRowStructure();
for (int rowNum=0; rowNum<numOfOpenTextFieldRows; rowNum++) {
TextField entityNameTextBox = new TextField();
entityOverview_GridPane.add(entityNameTextBox, 0 , rowNum+1);
TextField EntityLegalTypeTextBox = new TextField();
entityOverview_GridPane.add(EntityLegalTypeTextBox, 1, rowNum+1);
TextField EntityTypeTextBox = new TextField();
entityOverview_GridPane.add(EntityTypeTextBox, 2, rowNum+1);
DatePicker AcquisitionDateTextBox = new DatePicker();
entityOverview_GridPane.add(AcquisitionDateTextBox, 3, rowNum+1);
DatePicker DivestitureDateTextBox = new DatePicker();
entityOverview_GridPane.add(DivestitureDateTextBox, 4, rowNum+1);
TextField EINTextBox = new TextField();
entityOverview_GridPane.add(EINTextBox, 5, rowNum+1);
DatePicker taxableStartDateTextBox = new DatePicker();
entityOverview_GridPane.add(taxableStartDateTextBox, 6, rowNum+1);
DatePicker taxableEndDateTextBox = new DatePicker();
entityOverview_GridPane.add(taxableEndDateTextBox, 7, rowNum+1);
}
}
Create a model class, containing JavaFX properties representing the data that is editing by the text fields and date pickers in the row, and create a list of instances of that class.
Then each time you need to add a row, create a new instance of the model, add a row, and bind the properties in the model to the values in the controls in the row. Then to read the values, you just have to iterate through your list and and get the values from each object.
Here's a simpler version than what you describe, using two text fields and a single date picker, representing a person's first name, last name, and date of birth. First the model class:
import java.time.LocalDate;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
private final ObjectProperty<LocalDate> dateOfBirth = new SimpleObjectProperty<>();
public final StringProperty firstNameProperty() {
return this.firstName;
}
public final String getFirstName() {
return this.firstNameProperty().get();
}
public final void setFirstName(final String firstName) {
this.firstNameProperty().set(firstName);
}
public final StringProperty lastNameProperty() {
return this.lastName;
}
public final String getLastName() {
return this.lastNameProperty().get();
}
public final void setLastName(final String lastName) {
this.lastNameProperty().set(lastName);
}
public final ObjectProperty<LocalDate> dateOfBirthProperty() {
return this.dateOfBirth;
}
public final LocalDate getDateOfBirth() {
return this.dateOfBirthProperty().get();
}
public final void setDateOfBirth(final LocalDate dateOfBirth) {
this.dateOfBirthProperty().set(dateOfBirth);
}
}
Then the sample app
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class DynamicGridPaneExample extends Application {
private final List<Person> personList = new ArrayList<>();
private GridPane grid ;
private final DateTimeFormatter format = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) ;
private void addNewRow() {
// create a new person, and add to list:
Person person = new Person();
personList.add(person);
// create controls:
TextField firstNameTextField = new TextField();
TextField lastNameTextField = new TextField();
DatePicker dateOfBirthPicker = new DatePicker();
// bind controls to person:
firstNameTextField.textProperty().bindBidirectional(person.firstNameProperty());
lastNameTextField.textProperty().bindBidirectional(person.lastNameProperty());
dateOfBirthPicker.valueProperty().bindBidirectional(person.dateOfBirthProperty());
// add controls to grid:
grid.addRow(personList.size(), firstNameTextField, lastNameTextField, dateOfBirthPicker);
}
@Override
public void start(Stage primaryStage) {
grid = new GridPane();
grid.setHgap(2);
grid.setVgap(2);
grid.addRow(0, new Label("First Name"), new Label("Last Name"), new Label("Date of Birth"));
Button add = new Button("Add");
add.setOnAction(e -> addNewRow());
// just as a demo of getting the values:
Button process = new Button("Process data");
process.setOnAction(e -> {
for (Person person : personList) {
String firstName = person.getFirstName();
String lastName = person.getLastName();
LocalDate dateOfBirth = person.getDateOfBirth();
Object formattedDOB = dateOfBirth == null ? "" : format.format(dateOfBirth);
System.out.printf("%s %s %s %n", firstName, lastName, formattedDOB);
}
});
BorderPane root = new BorderPane(grid);
HBox buttons = new HBox(5, add, process);
buttons.setPadding(new Insets(5));
buttons.setAlignment(Pos.CENTER);
root.setBottom(buttons);
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
You should also consider using a TableView
, which basically has this functionality, plus a whole lot more infrastructure.