Java TextField OneEdit侦听器

Java TextField OneEdit侦听器,java,javafx-8,Java,Javafx 8,我正在尝试在javafx中使用TextField。 场景:我使用特定对象填充列表视图,并使用编辑按钮编辑与列表视图的列表单元格关联的对象。 当我点击“编辑”按钮时,它会将我重定向到一个具有编辑功能的窗格,在那里我可以编辑该对象的名称并使用“保存”按钮保存它。 所以我必须在save按钮上进行验证,使其启用和禁用。 如果在文本字段中编辑名称,则应启用“保存”按钮,否则应保持禁用状态。 我已经尝试在文本字段上使用不同的方法,如下所示 textField.textPorperty.addListener

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

textField.textPorperty.addListener(listener -> {
        //Logic to enable disable save button
});
当我使用列表视图时,此侦听器将旧值作为以前编辑的对象提供给我,该对象不满足我的条件。 我不能用

textField.focusedProperty().addListener((observableValue, oldValue, newValue) -> {});
因为它没有给我预期的行为


有人能帮我解决这个问题吗

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

  • 对初始值的引用(将文本设置为输入时,f.i.更改列表中的选择时)
  • 保持启用状态的布尔属性(低于它的称为缓冲)
  • 文本字段的侦听器,可根据需要更新启用状态
下面是一个非常简化的示例(只是让您开始学习),它将这些基础知识提取到一个名为BufferedPut的专用类中。缓冲在以下位置进行内部更改:

  • 如果设置了“主题”值或提交/放弃了更改,则设置为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);
    }
}
/**
*将提交/取消按钮的禁用属性绑定到实际更改。
* http://stackoverflow.com/q/29935643/203657
*/
公共类ManualBufferingDemo扩展应用程序{
私有父getContent(){
ObservableList persons=FXCollections.ObservableList(Person.persons(),
person->new Observable[]{person.lastNameProperty()});
ListView ListView=新的ListView(人);
TextField lastName=新的TextField();
消费者提交者=text->System.out.println(“提交:+text”);
BufferedTimePut buffer=新的BufferedTimePut(姓氏,提交人);
按钮保存=新按钮(“保存”);
save.setOnAction(e->{
commit();
});
save.disableProperty().bind(Bindings.not(buffer.bufferingProperty());
按钮取消=新按钮(“取消”);
取消设置操作(e->{
buffer.flush();
});
listView.getSelectionModel().SelectEditeProperty().addListener((源、旧、当前)->{
buffer.setSubject(current.lastNameProperty());
});
cancel.disableProperty().bind(Bindings.not(buffer.bufferingProperty());
VBox内容=新的VBox(列表视图、姓氏、保存、取消);
返回内容;
}
公共静态类缓冲输出{
私有ReadOnlyBooleanWrapper缓冲;
私有财产价值;
私有文本字段输入;
私人消费者委员会;
公共缓冲输入(文本字段输入,消费者提交者){
缓冲=新的ReadOnlyBooleanWrapper(此“缓冲”,false);
值=新的SimpleStringProperty(此“”);
这个输入=输入;
this.committer=提交者;
input.textProperty().addListener((源、旧、当前)->{
不动产(旧的、现有的);
});
setOnAction(e->commit());
}
私有void updateState(字符串旧,字符串当前){
if(isBuffering())返回;
if(value.get().equals(current))返回;
挫折(真);
}
public void setSubject(StringProperty值){
这个值=值;
input.setText(value.get());
挫折(假);
}
公共无效提交(){
accept(input.getText());
this.value.set(input.getText());
挫折(假);
}
公共图书馆{
input.setText(value.get());
挫折(假);
}
公共布尔值isBuffering(){
return buffering.get();
}
public ReadOnlyBooleanProperty bufferingProperty(){
返回buffering.getReadOnlyProperty();
}
私有void setBuffering(布尔缓冲区){
缓冲设置(buffer);
}
}
@凌驾
public void start(Stage primaryStage)引发异常{
setScene(新场景(getContent());
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
}

对于生产使用,视图和模型之间的这种直接耦合(f.i.当需要完整表单的缓冲时)不够好,可能需要进一步分离。在FX改编的臭名昭著的例子(非常粗糙)

中,请看它的用法,如果初始文本是“发出的”,它被改变为“发行”,然后返回“发行”。按钮是否保持启用状态?如果文本已发布更改为发布-按钮启用如果再次更改为发布而未保存以前更改的文本,则应保持禁用状态。