我正在尝试在javafx中使用TextField。 场景:我有用特定对象填充的列表视图和编辑按钮来编辑与列表视图的列表单元格相关联的对象。 当我单击编辑按钮时,它会将我重定向到具有编辑功能的窗格,我可以在其中编辑该对象的名称并使用保存按钮进行保存。 因此,我必须在保存按钮上进行验证,以使其启用和禁用。 如果我在文本字段中编辑名称,则应启用保存按钮,否则应保持禁用状态。 我尝试在文本字段上使用不同的方法,如下所示。
textField.textPorperty.addListener(listener -> {
//Logic to enable disable save button
});
当我使用列表视图时,此侦听器为我提供旧值,因为之前编辑的对象不符合我的条件。 我不能用
textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {});
因为它没有给我预期的行为。
有人可以帮我解决这个问题吗?
答案 0 :(得分:1)
您需要实现其他逻辑,以确定对textProperty的更改是否应更改按钮的启用状态。这需要:
下面是一个非常简单的示例 - 只是为了让您入门 - 将这些基础知识提取到名为BufferedTextInput的专用类中。内部更改缓冲:
可以根据需要实现更复杂的逻辑(例如,在检测到更改回原始值时不缓冲)。
/**
* Bind disable property of commit/cancel button to actual change.
* http://stackoverflow.com/q/29935643/203657
*/
public class ManualBufferingDemo extends Application {
private Parent getContent() {
ObservableList<Person> persons = FXCollections.observableList(Person.persons(),
person -> new Observable[] {person.lastNameProperty()});
ListView<Person> listView = new ListView<>(persons);
TextField lastName = new TextField();
Consumer<String> committer = text -> System.out.println("committing: " + text);
BufferedTextInput buffer = new BufferedTextInput(lastName, committer);
Button save = new Button("Save");
save.setOnAction(e -> {
buffer.commit();
});
save.disableProperty().bind(Bindings.not(buffer.bufferingProperty()));
Button cancel = new Button("Cancel");
cancel.setOnAction(e -> {
buffer.flush();
});
listView.getSelectionModel().selectedItemProperty().addListener((source, old, current) -> {
buffer.setSubject(current.lastNameProperty());
});
cancel.disableProperty().bind(Bindings.not(buffer.bufferingProperty()));
VBox content = new VBox(listView, lastName, save, cancel);
return content;
}
public static class BufferedTextInput {
private ReadOnlyBooleanWrapper buffering;
private StringProperty value;
private TextField input;
private Consumer<String> committer;
public BufferedTextInput(TextField input, Consumer<String> committer) {
buffering = new ReadOnlyBooleanWrapper(this, "buffering", false);
value = new SimpleStringProperty(this, "");
this.input = input;
this.committer = committer;
input.textProperty().addListener((source, old, current) -> {
updateState(old, current);
});
input.setOnAction(e -> commit());
}
private void updateState(String old, String current) {
if (isBuffering()) return;
if (value.get().equals(current)) return;
setBuffering(true);
}
public void setSubject(StringProperty value) {
this.value = value;
input.setText(value.get());
setBuffering(false);
}
public void commit() {
committer.accept(input.getText());
this.value.set(input.getText());
setBuffering(false);
}
public void flush() {
input.setText(value.get());
setBuffering(false);
}
public boolean isBuffering() {
return buffering.get();
}
public ReadOnlyBooleanProperty bufferingProperty() {
return buffering.getReadOnlyProperty();
}
private void setBuffering(boolean buffer) {
buffering.set(buffer);
}
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent()));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
对于生产用途,视图和模型之间的这种直接耦合(当需要缓冲完整形式时)不够好,可能需要进一步分离。请参阅BufferedObjectProperty及其在臭名昭着的AlbumManager示例(非常粗略)的外汇调整中的用法