java - TextField onEdit 监听器

标签 java javafx-8

我正在尝试在 javafx 中使用 TextField。 场景:我有填充了特定对象的 ListView 和编辑按钮来编辑与 ListView 的列表单元格关联的对象。 当我单击编辑按钮时,它会将我重定向到具有编辑功能的 Pane ,在其中我可以编辑该对象的名称并使用保存按钮保存它。 所以我必须对保存按钮进行验证以使其启用和禁用。 如果我在文本字段中编辑名称,那么它应该启用保存按钮,否则它应该保持禁用状态。 我尝试在文本字段上使用不同的方法,如下所示。

textField.textPorperty.addListener(listener -> {
        //Logic to enable disable save button
});

当我使用 ListView 时,此监听器为我提供旧值作为先前编辑的对象,该对象不满足我的条件。 我无法使用

textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {});

因为它没有给我预期的行为。

谁能帮我解决这个问题吗?

最佳答案

您需要实现额外的逻辑来决定对 textProperty 的更改是否应更改按钮的启用状态。这需要:

  • 对初始值的引用(将文本设置为输入,例如更改列表中的选择)
  • 一个 boolean 属性,用于保持启用状态(下面称为缓冲)
  • 文本字段的监听器,根据需要更新启用状态

下面是一个非常简化的示例 - 只是为了帮助您入门 - 它将这些基础知识提取到一个名为 BufferedTextInput 的专用类中。缓冲在内部更改:

  • 如果设置了“主题”值或提交/放弃了更改,则设置为 false
  • 在第一次更改文本字段时收到通知后设置为 true

可以根据需要实现更复杂的逻辑(例如在检测到返回原始值的更改时不进行缓冲)。

/**
 * 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);
    }
}

对于生产使用, View 和模型之间的这种直接耦合(例如,当需要完整表单的缓冲时)还不够好,可能需要进一步分离。请参阅BufferedObjectProperty及其在臭名昭著的 AlbumManager 的 FX 改编中的使用示例(非常粗略)

关于java - TextField onEdit 监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29935643/

相关文章:

Java在查看正确编码时会返回值吗?

java - 列表中的 add(...) 不能应用于 (...)

javafx - 从JavaFX输入字段中删除蓝框

java - 如何处理 java fx 8 中的按钮操作?

java - 如何使用 java runtime.exec() 和 ssh 到另一台机器来启动进程

基于 Java 的语法检查/基于规则的工具集

javafx - 使用 FXML 在 VBox 中包装标签文本

java - 如何确保按钮上的 Fxml 方法在监听器之前被调用?

javafx - 使 FlowPane 适合 ScrollPane

java - JSF:PanelGrid 不会呈现