I'm working on a project in which there are 2 tabs. On first tab's user interface there is a text field and a button. In the text field user can write any number till 100 and when he will press button Next, my application will go to the next tab on which there is a Gridpane with three columns A, B and C.
So what I want is whatever number user will enter in the first tab's text field according to that number it should add same number of rows with Textfields, Checkboxes and Datepicker in second tab's Gridpane.
With SceneBuilder it's very easy to create fixed sized Gridpane and then add elements inside it and give them fx:id, but dynamically it's complicated because I've to assign fx:id to each text field, checkboxes and Datepicker so I can retrieve it's data and can send to db.
Should I use Gridpane or is there any other solution to achieve the goal. It would be great help if someone could guide me on what needs to be done.
You cannot use loop logig in a fxml file. However you could implement some logic to add a specified number of rows. A <fx:root>
element can be used to create a fxml file for the individual rows:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.text.Text?>
<GridPane fx:id="root" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxml.grid.MainController">
<children>
<Text text="A"/>
<Text text="B" GridPane.columnIndex="1"/>
<Text text="C" GridPane.columnIndex="2"/>
</children>
</GridPane>
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.DatePicker?>
<fx:root type="javafx.scene.layout.GridPane" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxml.grid.SubController">
<children>
<TextField fx:id="text" GridPane.columnIndex="0" GridPane.rowIndex="$rowIndex" />
<CheckBox fx:id="checkBox" GridPane.columnIndex="1" GridPane.rowIndex="$rowIndex" />
<DatePicker fx:id="datePicker" GridPane.columnIndex="2" GridPane.rowIndex="$rowIndex" />
</children>
</fx:root>
public class MainController {
@FXML
private GridPane root;
private final List<SubController> subControllers = new ArrayList<>();
public void setRowNumber(int rows) throws IOException {
if (rows < subControllers.size()) {
// for simplicity only allow the number of rows to grow
throw new IllegalArgumentException();
}
for (int i = subControllers.size(); i < rows; i++) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sub.fxml"));
// add rowIndex to be used from fxml using $rowIndex
loader.getNamespace().put("rowIndex", subControllers.size() + 1);
loader.setRoot(root);
loader.load();
subControllers.add(loader.getController());
}
}
}
public class SubController {
@FXML
private TextField text;
@FXML
private CheckBox checkBox;
@FXML
private DatePicker datePicker;
}
int num = 6;
FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
Parent parent = loader.load();
loader.<MainController>getController().setRowNumber(num);
It shouldn't be too hard to add methods to the controllers to access individual elements.
Note that TableView
may also be worth a look.