JavaFX DatePicker with better text input features

Suppose we have a DatePicker without a date set. Therefore, if the user wants to enter a date, he needs to enter the entire date, including slashes: 10/11/2014

It would be nice if the user entered numbers, slashes could be automatically included (entering 10112014 correctly set the date).

Another thing is if a date is already set in the date picker (10/11/2014) and the user wants to enter a different date (01/11/2014), then he places the cursor at the beginning of the text and enter the date. The result will be something like 01/11/201410/11/2014. It would be better if, when entering text in the date selection field, it was automatically included in the insert mode, since the user entered the date when he overwrites the original date.

Is there any way to do this?

--- UPDATE ---

Thanks to Jose Pereda, I found a solution. I got his code and changed a bit:

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

} Then, to "improve" the DatePicker, I simply call this method, passing all my required datePicker instances as parameters

+4
source share
1 answer

Actually, you can fulfill both requests.

The first part is simple as you can use more than one date converter. Let's say you have the default format "dd / MM / uuuu" and the quick format "ddMMuuuu":

private final DateTimeFormatter fastFormatter = DateTimeFormatter.ofPattern("ddMMuuuu");
private final DateTimeFormatter defaultFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu");

Then you need to provide your own converter, keeping the default format for the method toString()and changing fromString()so that you can enter any of your formatters:

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();
    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();
});

, , . , 0 .

+3

Source: https://habr.com/ru/post/1568142/


All Articles