JavaFX如何检查所有动态添加的文本字段是否为空
JavaFX how to check if all dynamically added textfields are empty
我有一个 TextField 和两个连续的按钮。
一个按钮('add button')添加另一行 TextField 和另一对添加和删除按钮,另一个按钮删除该行。
删除按钮被禁用,而当前行是唯一的行,所以不能没有行。
仅当当前行的文本字段不为空且它是最后一个文本字段时,才会启用添加按钮。所以每一行都有一个禁用的 'add button' 除了最后一行。
我现在的问题是如何将 'add button' disableProperty 绑定到所有存在的文本字段并检查它们是否为空。事实上,我想我只需要检查最后一个文本字段,如果它是空的,我禁用最后一个 'add button' 如果写了最后一个 'add button' 保持禁用但当前行启用。
我找到了一个解决方法,我将按钮绑定到文本字段,然后如果我添加另一行我取消绑定按钮,禁用它,如果我删除一行我只启用最后一个按钮并绑定它反对文本字段。
这个解决方案看起来很笨重,我想知道是否有更优雅的解决方案 属性 绑定。
我的代码(有解决方法,所以你可以看到我想做什么):
public class Controller {
@FXML
private VBox VBox;
public ObservableList<TextField> oList = FXCollections.observableArrayList();
public ObservableList<Button> bList = FXCollections.observableArrayList();
public void initialize(){
createRow();
}
private void createRow(){
HBox box = new HBox(10);
TextField textField = new TextField();
Button addButton = new Button("Add row");
Button deleteButton = new Button("Delete");
box.getChildren().addAll(textField, addButton, deleteButton);
VBox.getChildren().add(box);
oList.add(textField);
bList.add(addButton);
addButton.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
addButton.disableProperty().unbind();
createRow();
textField.setDisable(true);
addButton.setDisable(true);
}
});
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
int idx = oList.indexOf(textField);
oList.remove(idx);
bList.remove(idx);
VBox.getChildren().remove(idx);
for(TextField tf : oList){
int i = oList.indexOf(tf);
if(oList.size()-1 == i){
tf.setDisable(false);
bList.get(i).disableProperty().bind(Bindings.isEmpty(tf.textProperty()));
}
}
}
});
}
}
还有两张截图:
添加了 4 行,全部 'add buttons' 禁用,也是最后一行,因为没有在文本字段中写入任何内容
我在这里删除了行 test1 和空行,所有 'add buttons' 仍然被禁用,除了最后一个,因为文本字段中有文本
感谢您的帮助!
PS:我知道在我的代码中 ObservableLists 不是必需的,但我正在尝试并让它们加入,因为我忘记了......
您可以创建一个 BooleanExpression
,如果列表中的所有 TextField
都为空,则 returns 为真。请注意,您需要重新创建该表达式作为 ObservableList<TextField>
更改的内容:
oList.addListener((ListChangeListener<? super TextField>) c -> {
addButton.disableProperty().unbind();
BooleanExpression allEmpty = oList.stream()
.map(tf -> BooleanExpression.booleanExpression(tf.textProperty().isEmpty()))
.reduce(new SimpleBooleanProperty(true), BooleanExpression::and);
addButton.disableProperty().bind(allEmpty);
});
每次添加或删除新的TextField
时,列表中的每个TextField
都会映射到empty
属性的BooleanExpression
TextField
。然后,所有的表达式将被加在一起。
注意:同样的方法也可以使用循环而不是流来完成。
注意:您需要在向列表中添加任何元素之前添加此侦听器。
我有一个 TextField 和两个连续的按钮。 一个按钮('add button')添加另一行 TextField 和另一对添加和删除按钮,另一个按钮删除该行。 删除按钮被禁用,而当前行是唯一的行,所以不能没有行。
仅当当前行的文本字段不为空且它是最后一个文本字段时,才会启用添加按钮。所以每一行都有一个禁用的 'add button' 除了最后一行。
我现在的问题是如何将 'add button' disableProperty 绑定到所有存在的文本字段并检查它们是否为空。事实上,我想我只需要检查最后一个文本字段,如果它是空的,我禁用最后一个 'add button' 如果写了最后一个 'add button' 保持禁用但当前行启用。
我找到了一个解决方法,我将按钮绑定到文本字段,然后如果我添加另一行我取消绑定按钮,禁用它,如果我删除一行我只启用最后一个按钮并绑定它反对文本字段。 这个解决方案看起来很笨重,我想知道是否有更优雅的解决方案 属性 绑定。
我的代码(有解决方法,所以你可以看到我想做什么):
public class Controller {
@FXML
private VBox VBox;
public ObservableList<TextField> oList = FXCollections.observableArrayList();
public ObservableList<Button> bList = FXCollections.observableArrayList();
public void initialize(){
createRow();
}
private void createRow(){
HBox box = new HBox(10);
TextField textField = new TextField();
Button addButton = new Button("Add row");
Button deleteButton = new Button("Delete");
box.getChildren().addAll(textField, addButton, deleteButton);
VBox.getChildren().add(box);
oList.add(textField);
bList.add(addButton);
addButton.disableProperty().bind(Bindings.isEmpty(textField.textProperty()));
addButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
addButton.disableProperty().unbind();
createRow();
textField.setDisable(true);
addButton.setDisable(true);
}
});
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent actionEvent) {
int idx = oList.indexOf(textField);
oList.remove(idx);
bList.remove(idx);
VBox.getChildren().remove(idx);
for(TextField tf : oList){
int i = oList.indexOf(tf);
if(oList.size()-1 == i){
tf.setDisable(false);
bList.get(i).disableProperty().bind(Bindings.isEmpty(tf.textProperty()));
}
}
}
});
}
}
还有两张截图:
添加了 4 行,全部 'add buttons' 禁用,也是最后一行,因为没有在文本字段中写入任何内容
我在这里删除了行 test1 和空行,所有 'add buttons' 仍然被禁用,除了最后一个,因为文本字段中有文本
感谢您的帮助!
PS:我知道在我的代码中 ObservableLists 不是必需的,但我正在尝试并让它们加入,因为我忘记了......
您可以创建一个 BooleanExpression
,如果列表中的所有 TextField
都为空,则 returns 为真。请注意,您需要重新创建该表达式作为 ObservableList<TextField>
更改的内容:
oList.addListener((ListChangeListener<? super TextField>) c -> {
addButton.disableProperty().unbind();
BooleanExpression allEmpty = oList.stream()
.map(tf -> BooleanExpression.booleanExpression(tf.textProperty().isEmpty()))
.reduce(new SimpleBooleanProperty(true), BooleanExpression::and);
addButton.disableProperty().bind(allEmpty);
});
每次添加或删除新的TextField
时,列表中的每个TextField
都会映射到empty
属性的BooleanExpression
TextField
。然后,所有的表达式将被加在一起。
注意:同样的方法也可以使用循环而不是流来完成。
注意:您需要在向列表中添加任何元素之前添加此侦听器。