JavaFx:如何验证在 运行 时间创建的多个文本字段?
JavaFx: How to validate mutilple TextFields creating at run time?
我在 运行 时使用 for 循环创建多个 TextField,并将它们添加到 Gridpane(有 8 列)内部,如下所示:
public static GridPane table(int rows){
GridPane table = new GridPane();
for(int i=0; i<rows; i++){
JFXTextField textField1 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField2 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField3 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField4 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField5 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField6 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField7 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField8 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
//add them to the GridPane
table.add(textField1, 0, i+1);
table.add(textField2, 1, i+1);
table.add(textField3, 2, i+1);
table.add(textField4, 3, i+1);
table.add(textField5, 4, i+1);
table.add(textField6, 5, i+1);
table.add(textField7, 6, i+1);
table.add(textField8, 7, i+1);
}
return table;
}
接下来,我将在特定行和列的 table 中为 return 组件创建另一种方法,如下所示:
public static Node getComponent (int row, int column, GridPane table) {
for (Node component : table.getChildren()) { // loop through every node in the table
if(GridPane.getRowIndex(component) == row &&
GridPane.getColumnIndex(component) == column) {
return component;
}
}
return null;
}
问题在这里:我想验证每个 TextField,所以如果用户忘记在任何 TextField 中写入,我想禁用 Button,为此目的我正在使用这样的绑定:
private void validatingGrid() {
GridPane table = (GridPane) anchorPane().getChildren().get(0);
for(int i=1 ; i<=comboBox().getValue(); i++){
JFXTextField text0 = ((JFXTextField)getComponent (i, 0, table));
JFXTextField text1 = ((JFXTextField)getComponent (i, 1, table));
JFXTextField text2 = ((JFXTextField)getComponent (i, 2, table));
JFXTextField text3 = ((JFXTextField)getComponent (i, 3, table));
JFXTextField text4 = ((JFXTextField)getComponent (i, 4, table));
JFXTextField text5 = ((JFXTextField)getComponent (i, 5, table));
JFXTextField text6 = ((JFXTextField)getComponent (i, 6, table));
JFXTextField text7 = ((JFXTextField)getComponent (i, 7, table));
button.disableProperty().bind(
Bindings.isEmpty(text0.textProperty())
.or(Bindings.isEmpty(text1.textProperty()))
.or(Bindings.isEmpty(text2.textProperty()))
.or(Bindings.isEmpty(text3.textProperty()))
.or(Bindings.isEmpty(text4.textProperty()))
.or(Bindings.isEmpty(text5.textProperty()))
.or(Bindings.isEmpty(text6.textProperty()))
.or(Bindings.isEmpty(text7.textProperty()))
);
}
}
但是发生的事情是它只验证最后一行,假设我在网格窗格中创建了 3 行 textfeilds,那么它只验证第 3 行而不是第 1 行和第 2 行,并且在第 3 行条目的基础上它启用了按钮,但我希望在验证所有行后它应该启用按钮,否则不会。请帮助我如何实现这一目标。
您的绑定逻辑是正确的。然而,由于 for loop
[for(int i=1 ; i<=comboBox().getValue(); i++)
] 的问题,这毁了你的工作。所有 TextFields
都位于 列索引 0
,唯一变化的是 行索引 。因此,您应该对 for loop
中的所有 TextFields
使用 getComponent(i, 0, table);
,而无需将 列索引 更改为 1
, 2
.. 等等。但这也不能解决问题,因为在每个循环中,您都将 ALL TextFields
分配给相同的 index 然后在每个循环中覆盖它,直到它们都指向索引 comboBox().getValue()
和列 0
处的 TextField
(这就是为什么它在最后一行工作的原因你提到过)。
我会建议不同的方法,像这样:
首先你需要一种方法来检查所有其他 TextFields
是否已填充/不为空:
/**
* Check if all the TextFields are filled and not empty
* @param table
*/
private static boolean isAllFilled(GridPane table){
for(Node node : table.getChildren()){ // cycle through every component in the table (GridPane)
if(node instanceof TextField){ // if it's a TextField
// after removing the leading spaces, check if it's empty
if(((TextField)node).getText().trim().isEmpty()){
return false; // if so, return false
}
}
}
return true;
}
其次,聆听 Table 中每个 TextField
的文本更改,并在每次更改时检查是否所有其他 TextField
已填充/未填充空:
/**
* To Validate the Table (GridPane)
* This method should be added to the tabPane change listener
* @param table
* @param button
*/
private void validateTable(GridPane table, Button button) {
for(Node node : table.getChildren()){ // cycle through every component in the table (GridPane)
if(node instanceof TextField){ // if it's a TextField
((TextField)node).textProperty().addListener((obs, old, newV)->{ // add a change listener to every TextField
// then check if the new value is not empty AND all other TextFields are not empty
if(!newV.trim().isEmpty()&&isAllFilled(table)){
button.setDisable(false); // then make the button active again
}
else{
button.setDisable(true); // or else, make it disable until it achieves the required condition
}
});
}
}
另外,你需要设置按钮创建后禁用一次
Button button = new Button("Test");
button.setDisable(true);
最后,需要在tabPane
Change Listener Block中添加方法:
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
.........
.........
.........
validateTable((GridPane) anchorPane().getChildren().get(0), test);
}
测试
我在 运行 时使用 for 循环创建多个 TextField,并将它们添加到 Gridpane(有 8 列)内部,如下所示:
public static GridPane table(int rows){
GridPane table = new GridPane();
for(int i=0; i<rows; i++){
JFXTextField textField1 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField2 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField3 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField4 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField5 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField6 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField7 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
JFXTextField textField8 = new JFXTextField();
textField1.setAlignment(Pos.CENTER);
//add them to the GridPane
table.add(textField1, 0, i+1);
table.add(textField2, 1, i+1);
table.add(textField3, 2, i+1);
table.add(textField4, 3, i+1);
table.add(textField5, 4, i+1);
table.add(textField6, 5, i+1);
table.add(textField7, 6, i+1);
table.add(textField8, 7, i+1);
}
return table;
}
接下来,我将在特定行和列的 table 中为 return 组件创建另一种方法,如下所示:
public static Node getComponent (int row, int column, GridPane table) {
for (Node component : table.getChildren()) { // loop through every node in the table
if(GridPane.getRowIndex(component) == row &&
GridPane.getColumnIndex(component) == column) {
return component;
}
}
return null;
}
问题在这里:我想验证每个 TextField,所以如果用户忘记在任何 TextField 中写入,我想禁用 Button,为此目的我正在使用这样的绑定:
private void validatingGrid() {
GridPane table = (GridPane) anchorPane().getChildren().get(0);
for(int i=1 ; i<=comboBox().getValue(); i++){
JFXTextField text0 = ((JFXTextField)getComponent (i, 0, table));
JFXTextField text1 = ((JFXTextField)getComponent (i, 1, table));
JFXTextField text2 = ((JFXTextField)getComponent (i, 2, table));
JFXTextField text3 = ((JFXTextField)getComponent (i, 3, table));
JFXTextField text4 = ((JFXTextField)getComponent (i, 4, table));
JFXTextField text5 = ((JFXTextField)getComponent (i, 5, table));
JFXTextField text6 = ((JFXTextField)getComponent (i, 6, table));
JFXTextField text7 = ((JFXTextField)getComponent (i, 7, table));
button.disableProperty().bind(
Bindings.isEmpty(text0.textProperty())
.or(Bindings.isEmpty(text1.textProperty()))
.or(Bindings.isEmpty(text2.textProperty()))
.or(Bindings.isEmpty(text3.textProperty()))
.or(Bindings.isEmpty(text4.textProperty()))
.or(Bindings.isEmpty(text5.textProperty()))
.or(Bindings.isEmpty(text6.textProperty()))
.or(Bindings.isEmpty(text7.textProperty()))
);
}
}
但是发生的事情是它只验证最后一行,假设我在网格窗格中创建了 3 行 textfeilds,那么它只验证第 3 行而不是第 1 行和第 2 行,并且在第 3 行条目的基础上它启用了按钮,但我希望在验证所有行后它应该启用按钮,否则不会。请帮助我如何实现这一目标。
您的绑定逻辑是正确的。然而,由于 for loop
[for(int i=1 ; i<=comboBox().getValue(); i++)
] 的问题,这毁了你的工作。所有 TextFields
都位于 列索引 0
,唯一变化的是 行索引 。因此,您应该对 for loop
中的所有 TextFields
使用 getComponent(i, 0, table);
,而无需将 列索引 更改为 1
, 2
.. 等等。但这也不能解决问题,因为在每个循环中,您都将 ALL TextFields
分配给相同的 index 然后在每个循环中覆盖它,直到它们都指向索引 comboBox().getValue()
和列 0
处的 TextField
(这就是为什么它在最后一行工作的原因你提到过)。
我会建议不同的方法,像这样:
首先你需要一种方法来检查所有其他 TextFields
是否已填充/不为空:
/**
* Check if all the TextFields are filled and not empty
* @param table
*/
private static boolean isAllFilled(GridPane table){
for(Node node : table.getChildren()){ // cycle through every component in the table (GridPane)
if(node instanceof TextField){ // if it's a TextField
// after removing the leading spaces, check if it's empty
if(((TextField)node).getText().trim().isEmpty()){
return false; // if so, return false
}
}
}
return true;
}
其次,聆听 Table 中每个 TextField
的文本更改,并在每次更改时检查是否所有其他 TextField
已填充/未填充空:
/**
* To Validate the Table (GridPane)
* This method should be added to the tabPane change listener
* @param table
* @param button
*/
private void validateTable(GridPane table, Button button) {
for(Node node : table.getChildren()){ // cycle through every component in the table (GridPane)
if(node instanceof TextField){ // if it's a TextField
((TextField)node).textProperty().addListener((obs, old, newV)->{ // add a change listener to every TextField
// then check if the new value is not empty AND all other TextFields are not empty
if(!newV.trim().isEmpty()&&isAllFilled(table)){
button.setDisable(false); // then make the button active again
}
else{
button.setDisable(true); // or else, make it disable until it achieves the required condition
}
});
}
}
另外,你需要设置按钮创建后禁用一次
Button button = new Button("Test");
button.setDisable(true);
最后,需要在tabPane
Change Listener Block中添加方法:
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>(){
.........
.........
.........
validateTable((GridPane) anchorPane().getChildren().get(0), test);
}
测试