Use JavaFX / TextFormatter

environment

What is Text Formatter?

TextFormatter <T> is a class that handles "conversion and modification" in the text input control, and is used by setting it in the text input control such as TextField and TextArea. It has the following roles.

--Holds a data model of type T --Handling mutual conversion between text representation and original type T --Process Change, which is a state change of text input (filter)

Data model retention

TextFormatter holds the data model of the type specified by the type argument T.

You can retrieve it with getValue () and get the property with valueProperty (), so you can also do property binding. Also, this value and the text input control text will change following each other regardless of which one is rewritten.

StringConverter

For example, if you want to edit Integer type data with TextField, you need to convert it to a text representation and display it. Also, to treat the edited value as an Integer, you need to parse the text. StringConverter is an interface that provides a framework for such types of interconversion.

JavaFX already has a built-in StringConverter for common types, so you can choose from here to use. Package javafx.util.converter

filter

TextFormatter.Change TextFormatter.Change is a class that holds the state change of the text input control. Each time a text input control is ** manipulated **, a Change is generated and passed to the TextFormatter. It has the following information.

--Selection range before and after change (caret and anchor position) --The range of text that will be removed by the change --Text inserted after change --Type of change (add, delete, replace) --Whole text before and after the change

TextFormatter.Change (JavaFX): API Document

What is a filter?

TextFormatter has the function to process this Change. In other words, you can replace the changes you don't like with Change with other changes. In TextFormatter, this operation is called a filter and can be implemented as a functional interface that receives Change and returns Change.

UnaryOperator<TextFormatter.Change> filter;

About selection

The selection is defined as between the anchor and the caret. The caret is the current position where you are typing, but be aware that it has different implications when it is at the beginning and end of the selection.

a.png

Example of using TextFormatter

TextFormatter is created by passing StringConverter, filter, or both. TextFormatter (JavaFX): API Document

Below is a sample.

Text field to edit the currency of Japanese Yen

Let's use the built-in class CurrencyStringConverter which displays Number as currency.

Example


TextFormatter<Number> currencyFormatter = new TextFormatter<>(
        new CurrencyStringConverter(Locale.JAPAN), 
        0, 
        change -> {
    //Selection cannot be before the first character
    change.setAnchor(Math.max(1, change.getAnchor()));
    change.setCaretPosition(Math.max(1, change.getCaretPosition()));
    //Text change range cannot be before the first character
    change.setRange(Math.max(1, change.getRangeStart()), Math.max(1, change.getRangeEnd()));
    return change;
});
textField1.setTextFormatter(currencyFormatter);

b.png

"" Is always displayed at the beginning. CurrencyStringConverter performs mutual conversion such as "¥ 100000" → 100000 → "¥ 100,000" when the enter key is pressed, and 100000 is set to value of TextFormatter.

Thanks to value, the representation of the text field and the data model can be treated separately. The following is an example of turning the letters red when the number is 30000 or less.

Example


currencyFormatter.valueProperty().addListener((o, oldValue, newValue) -> {
    textField1.setStyle(newValue.intValue() <= 30000 ? 
            "-fx-text-fill: red" : "-fx-text-fill: black");
});

9.png

In addition, a filter is passed to this TextFormatter so that the first character" \ "cannot be selected, deleted, or changed. Below is a full selection by pressing Ctrl-A.

c.png

Text field where you can only enter numbers

Example


Pattern notNumberPattern = Pattern.compile("[^0-9]+");
TextFormatter<String> lowerFormatter = new TextFormatter<>(change -> {
    String newStr = notNumberPattern.matcher(change.getText()).replaceAll("");
    int diffcount = change.getText().length() - newStr.length();
    change.setAnchor(change.getAnchor() - diffcount);
    change.setCaretPosition(change.getCaretPosition() - diffcount);
    change.setText(newStr);
    return change;
});
textField2.setTextFormatter(lowerFormatter);

This TextFormatter is passed only the filter, and it is a mechanism to replace the change difference text with only numbers every time. Below is the text field after typing "2017-04-01T12: 00: 00".

e.png

Since the filter converts each update, it works not only by key input but also by copy and paste and value setting by TextField :: setText.

Text field to edit IPv4 address

I made an IPv4 address field where you can enter a numerical value for each byte. You cannot edit anything other than numbers, and typing "." Selects the byte to the right.

f.png

Inet4AddressFormatter.java

Example


textField3.setTextFormatter(new Inet4AddressFormatter(null));

There is a limit to determining the user's mouse operation and key operation from the change difference. If you want to make something elaborate, you should consider another approach.

Another use of TextFormatter

Since the filter is convenient because it can know only the changed part of the text field at once, it seems that it is often used easily as an alternative to the ChangeListener of the text field.

reference

Yutchi's Blog: I also tried Formatted Text added in JDK8u40. Source: GitHub FXLM: GitHub

Recommended Posts

Use JavaFX / TextFormatter
Use JavaFX Clipboard API
[JavaFX] [Java8] How to use GridPane
Use before_action! !!
JavaFX text
Use XMLHttpRequest
Use ActiveStorage!
JavaFx memorandum
Use AutosizingTextView