JavaFXDatePicker具有更好的键入功能

JavaFXDatePicker具有更好的键入功能,java,javafx,Java,Javafx,假设我们有一个没有日期集的日期选择器。 因此,如果用户想要键入日期,他需要键入整个日期,包括斜杠: 2014年11月10日 如果在用户键入数字时,斜杠可以自动包含(键入10112014可以正确设置日期),那就好了 另一件事是,如果日期选择器(2014年11月10日)上已经设置了一个日期,并且用户想要键入另一个日期(2014年11月1日),那么他将光标放在文本的开头并键入日期。结果大概是2011年11月1日410/11/2014。如果在日期选择器的字段上键入时,它会自动进入插入模式,这样当用户键入

假设我们有一个没有日期集的日期选择器。 因此,如果用户想要键入日期,他需要键入整个日期,包括斜杠: 2014年11月10日

如果在用户键入数字时,斜杠可以自动包含(键入10112014可以正确设置日期),那就好了

另一件事是,如果日期选择器(2014年11月10日)上已经设置了一个日期,并且用户想要键入另一个日期(2014年11月1日),那么他将光标放在文本的开头并键入日期。结果大概是2011年11月1日410/11/2014。如果在日期选择器的字段上键入时,它会自动进入插入模式,这样当用户键入日期时,它会覆盖原始日期

有办法做这些事情吗

---更新---

多亏了JoséPereda,我找到了解决办法。我得到了他的密码并做了一些修改:

public static void enhanceDatePickers(DatePicker... datePickers) {
for (DatePicker datePicker : datePickers) {
    datePicker.setConverter(new StringConverter<LocalDate>() {

        private final DateTimeFormatter fastFormatter1 = DateTimeFormatter.ofPattern("ddMMuuuu");
        private final DateTimeFormatter fastFormatter2 = DateTimeFormatter.ofPattern("d/M/u");
        private final DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu");

        @Override
        public String toString(LocalDate object) {
            return object.format(defaultFormatter);
        }

        @Override
        public LocalDate fromString(String string) {
            try{ return LocalDate.parse(string, fastFormatter1); } catch(DateTimeParseException ignored){}
            try{ return LocalDate.parse(string, fastFormatter2); } catch(DateTimeParseException ignored){}
            return LocalDate.parse(string, defaultFormatter);
        }
    });

    TextField textField = datePicker.getEditor();
    textField.addEventHandler(KeyEvent.KEY_TYPED, event -> {
        if (!"0123456789/".contains(event.getCharacter())) {
            return;
        }
        if ("/".equals(event.getCharacter()) && (textField.getText().isEmpty() || textField.getText().charAt(textField.getCaretPosition()-1)=='/')) {
            //If the users types slash again after it has been added, cancels it.
            System.out.println("Cancelando o bagulho!");
            event.consume();
        }
        textField.selectForward();
        if (!event.getCharacter().equals("/") && textField.getSelectedText().equals("/")) {
            textField.cut();
            textField.selectForward();
        }
        textField.cut();

        Platform.runLater(() -> {
            String textUntilHere = textField.getText(0, textField.getCaretPosition());
            if (textUntilHere.matches("\\d\\d") || textUntilHere.matches("\\d\\d/\\d\\d")) {
                String textAfterHere = "";
                try { textAfterHere = textField.getText(textField.getCaretPosition()+1, textField.getText().length()); } catch (Exception ignored) {}
                int caretPosition = textField.getCaretPosition();
                textField.setText(textUntilHere + "/" + textAfterHere);
                textField.positionCaret(caretPosition+1);
            }
        });
    });
}
publicstaticvoidenhancedatepicker(日期选择器…日期选择器){
for(日期选择器日期选择器:日期选择器){
datePicker.setConverter(新的StringConverter(){
私有最终DateTimeFormatter FastFormatter 1=模式的DateTimeFormatter.of(“DDMMUUU”);
私有最终DateTimeFormatter FastFormatter 2=模式的DateTimeFormatter.of(“d/M/u”);
私有最终DateTimeFormatter defaultFormatter=模式的DateTimeFormatter.of(“dd/MM/UUU”);
@凌驾
公共字符串toString(LocalDate对象){
返回object.format(defaultFormatter);
}
@凌驾
public LocalDate fromString(字符串){
尝试{return LocalDate.parse(string,fastFormatter1);}catch(DateTimeParseException被忽略){}
尝试{return LocalDate.parse(string,fastFormatter2);}catch(DateTimeParseException被忽略){}
返回LocalDate.parse(字符串,defaultFormatter);
}
});
TextField TextField=datePicker.getEditor();
textField.addEventHandler(KeyEvent.KEY_键入,事件->{
如果(!“0123456789/”.contains(event.getCharacter())){
返回;
}
如果(“/”.equals(event.getCharacter())&&(textField.getText().isEmpty()| | textField.getText().charAt(textField.getCaretPosition()-1)=='/')){
//如果用户在添加斜杠后再次键入斜杠,则会取消斜杠。
System.out.println(“Cancelando bagulho!”);
event.consume();
}
textField.selectForward();
如果(!event.getCharacter().equals(“/”&&textField.getSelectedText().equals(“/”){
textField.cut();
textField.selectForward();
}
textField.cut();
Platform.runLater(()->{
字符串textUntilHere=textField.getText(0,textField.getCaretPosition());
if(textUntilHere.matches(“\\d\\d”)| | textUntilHere.matches(“\\d\\d/\\d\\d”)){
字符串textAfterHere=“”;
请尝试{textAfterHere=textField.getText(textField.getCaretPosition()+1,textField.getText().length());}catch(忽略异常){
int caretPosition=textField.getCaretPosition();
textField.setText(textUntilHere+“/”+textAfterHere);
textField.positionCaret(caretPosition+1);
}
});
});
}
}
然后,为了“增强”DatePicker,我只调用此方法,将所有所需的DatePicker实例作为参数传递

实际上,您可以执行这两个请求

第一部分很简单,因为您可以使用多个日期转换器。假设您有一个默认格式“dd/MM/uuu”和一个快速格式“ddmmuuu”:

然后,您必须提供自定义转换器,保留
toString()
方法的默认格式,并修改
fromString()
,以便您可以使用任何格式设置程序键入:

DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setConverter(new StringConverter<LocalDate>() {

    @Override
    public String toString(LocalDate object) {
        return object.format(defaultFormatter);
    }

    @Override
    public LocalDate fromString(String string) {
        try{
            return LocalDate.parse(string, fastFormatter);
        } catch(DateTimeParseException dtp){}

        return LocalDate.parse(string, defaultFormatter);
    }
});
但是,如果不键入,则不仅需要删除下一个数字,还需要删除编辑器上的下一个斜杠:

datePicker.getEditor().setOnKeyTyped(event -> {
    if (!"0123456789/".contains(event.getCharacter())) {
        return;
    }
    datePicker.getEditor().selectForward();
    if(!event.getCharacter().equals("/") && 
       datePicker.getEditor().getSelectedText().equals("/")){
        datePicker.getEditor().cut();
        datePicker.getEditor().selectForward();
    }
    datePicker.getEditor().cut();
});

注意:无论是否使用斜杠,此选项都有效。另外请注意,必要时您必须键入0前导数字。

非常好!为了满足我的需要,我对它做了一点修改,准备用我的代码更新我的问题。感谢您发回您的解决方案。为什么要使用cut()(到剪贴板)?只删除当前选择?不幸的是,没有
日期选择器。getEditor().getSelection().clear()
或类似的选项。更麻烦的方法可能是
datePicker.getEditor().replaceText(datePicker.getEditor().getSelection(),“”)
。有没有办法在多个字段上重用此代码?或者我必须在任何字段上重复相同的内容?当然,只需这样称呼它:
增强日期选择器(myFirstDatePicker,anotherDatePicker,不久)
。这是因为该方法使用varargs(
Datepicker…datePickers
)来接受您希望传递的该类型参数的数量…谢谢,这对我帮助很大,并为我节省了很多代码行。我从JavaFX开始,所以我有点迷茫。toString()应该处理空的LocalDate(如果没有日期集,则为NPE)
datePicker.getEditor().setOnKeyTyped(event -> {
    if (!"0123456789/".contains(event.getCharacter())) {
        return;
    }
    datePicker.getEditor().selectForward();
    datePicker.getEditor().cut();
});
datePicker.getEditor().setOnKeyTyped(event -> {
    if (!"0123456789/".contains(event.getCharacter())) {
        return;
    }
    datePicker.getEditor().selectForward();
    if(!event.getCharacter().equals("/") && 
       datePicker.getEditor().getSelectedText().equals("/")){
        datePicker.getEditor().cut();
        datePicker.getEditor().selectForward();
    }
    datePicker.getEditor().cut();
});