0

I'm looking to format a phone number in real time as it is typed into a TextField. The goal is to add a "separator" (a space, a dash, a dot...) between the different digits forming the phone number according to the country. By default France : 06 23 65 14 85 But also for other countries as the international format French : +33 6 23 65 14 85 Or the german international format : +xx xxx xxx xx xxx

For this, I have a Listener that looks permanently when a new number is added in the TextField. The program then takes care of detecting the format of the phone number that is being entered, and depending on that, the program uses a "format" that I created myself to modify the format of the string.

The problem is that the user's cursor is constantly moving while reformatting the string. If the user deletes or selects a zone and then deletes it... each time, the cursor moves to the beginning or the end of the string which is very annoying to write.

Would you have a solution to change the format of the string in real time while making sure that the cursor is in the right place? The only alternative I found for the moment is a lib but that seems to be difficult to maintain so I'd rather do it myself. Otherwise I have to wait for the unfocus on the graphic component and change the format after that, but that's not what I want.

I provide you my code below, excuse me if there is a little bit of French in it, I sometimes write some.

import java.util.function.UnaryOperator;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;
import javafx.util.converter.IntegerStringConverter;

public class FormPhoneNumber {

    private StringProperty textPropertyFromComponent = new SimpleStringProperty();
    private TextField tf;
    private String separator;
    private String last = "";
    private int lastCaretPosition = 0;
    private ChangeListener<String> updateText;

    public FormPhoneNumber(TextField textField, String separator) {
        this.textPropertyFromComponent = textField.textProperty();
        this.tf = textField;


//On unfocus
//        tf.focusedProperty().addListener((ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) -> {
//            if (t1 == false) {
//                System.out.println("i");
//            }
//        });
        
        if (separator != null && !separator.isEmpty()) {
            this.separator = separator;
        } else {
            separator = " ";
        }
        checkNumberFormat();
    }

    private void checkNumberFormat() {

//Listener on write in the textfield
        updateText = (ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
            if (newValue == null || newValue.isEmpty()) {
                return;
            }

//My customs formatters
            if (newValue.startsWith("+33")) {
//                System.out.println("FRANCE");
                String resultat = getPhoneNumberFormatted(newValue, "###-#-##-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 17);
            } else if (newValue.startsWith("+49")) {
//                System.out.println("ALLEMAGNE");
                String resultat = getPhoneNumberFormatted(newValue, "###-###-###-##-###");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 18);
            } else if (newValue.startsWith("+34")) {
//                System.out.println("ESPAGNE");
                String resultat = getPhoneNumberFormatted(newValue, "###-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.replaceAll(separator, "").startsWith("+3245") || newValue.replaceAll(separator, "").startsWith("+3249")) {
//                System.out.println("BELGIQUE GSM");
                String resultat = getPhoneNumberFormatted(newValue, "###-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.replaceAll(separator, "").startsWith("+322") || newValue.replaceAll(separator, "").startsWith("+323") || newValue.replaceAll(separator, "").startsWith("+329")) {
//                System.out.println("BELGIQUE AUTRE 1");
                String resultat = getPhoneNumberFormatted(newValue, "###-#-###-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 15);
            } else if (newValue.startsWith("+32")) {
//                System.out.println("BELGIQUE");
                String resultat = getPhoneNumberFormatted(newValue, "###-##-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 15);
            } else if (newValue.replaceAll(separator, "").startsWith("+3526")) {
//                System.out.println("LUXEMBOURG 1");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-###-###");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+352")) {
//                System.out.println("LUXEMBOURG AUTRE");
                String resultat = getPhoneNumberFormatted(newValue, "####-##-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+377")) {
//                System.out.println("MONACO");
                String resultat = getPhoneNumberFormatted(newValue, "####-##-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+41")) {
//                System.out.println("SUISSE");
                String resultat = getPhoneNumberFormatted(newValue, "###-##-###-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.replaceAll(separator, "").startsWith("+390")) {
//                System.out.println("ITALIE FIXE");
                String resultat = getPhoneNumberFormatted(newValue, "###-##-####-####");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.replaceAll(separator, "").startsWith("+393")) {
//                System.out.println("ITALIE PORTABLE");
                String resultat = getPhoneNumberFormatted(newValue, "###-###-###-####");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+39")) {
//                System.out.println("ITALIE AUTRE");
                String resultat = getPhoneNumberFormatted(newValue, "###-##-####-####");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+376")) {
//                System.out.println("ANDORRE");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-###-###");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 16);
            } else if (newValue.startsWith("+590")) {
//                System.out.println("GUADELOUPE");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 17);
            } else if (newValue.startsWith("+596")) {
//                System.out.println("MARTINIQUE");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 17);
            } else if (newValue.startsWith("+594")) {
//                System.out.println("GUYANE");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 17);
            } else if (newValue.startsWith("+262")) {
//                System.out.println("REUNION ET MAYOTTE");
                String resultat = getPhoneNumberFormatted(newValue, "####-###-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 17);
            } else if (newValue.startsWith("+687")) {
//                System.out.println("NOUVELLE-CALEDONIE");
                String resultat = getPhoneNumberFormatted(newValue, "####-##-##-##");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 13);
            } else if (newValue.startsWith("+")) {
//                System.out.println("AUTRE - PAYS NON REFERENCE");
                String resultat = getPhoneNumberFormatted(newValue, "######################");
                int caretPosition = tf.getCaretPosition();
                setResult(resultat, caretPosition, oldValue, newValue, 22);
            } else if (newValue.length() >= 3) {
                if (Character.isDigit(newValue.charAt(0))) {
//                    System.out.println("France Nationnal");
                    String resultat = getPhoneNumberFormatted(newValue, "##-##-##-##-##");
                    int caretPosition = tf.getCaretPosition();
                    setResult(resultat, caretPosition, oldValue, newValue, 14);
                }
            }
        };
        textPropertyFromComponent.addListener(updateText);
    }

//My attempt to put the cursor in the right place, but VERY scary code
    private void setResult(String resultat, int caretPosition, String oldValue, String newValue, int maxLength) {
        Platform.runLater(() -> {
            if (resultat.length() <= maxLength && newValue != null && oldValue != null) {
                textPropertyFromComponent.set(resultat);
//                int diffAddLetter = newValue.length() - oldValue.length();
//                int diffRemLetter = oldValue.length() - newValue.length();
//                System.out.println("oldValue = " + oldValue);
//                System.out.println("newValue = " + newValue);
//                System.out.println("resultat = " + resultat);
//                System.out.println("test = " + last);
//                if (newValue.length() == maxLength) {
//                    if (!"".equals(last)) {
//                        tf.positionCaret(caretPosition + 1);
//                    }
//                } else if (diffAddLetter > 0) {
//                    System.out.println("diffAddLetter = " + diffAddLetter);
//                    System.out.println("lastCaretPosition = " + lastCaretPosition);
//                    System.out.println("caretPosition = " + caretPosition);
//                    if ("".equals(last)) {
//                        if (StringUtils.countMatches(oldValue, separator) < StringUtils.countMatches(newValue, separator)) {
//                            tf.positionCaret(caretPosition + 1);
//                        } else {
//                            tf.positionCaret(caretPosition);
//                        }
//                        System.out.println("a1");
//                    } else {
//                        tf.positionCaret(caretPosition + diffAddLetter);
//                        System.out.println("a2");
//                    }
//                    if (lastCaretPosition == caretPosition) {
//                        last = "";
//                    } else {
//                        last = oldValue;
//                    }
//                } else if (diffRemLetter > 0) {
//                    System.out.println("lastCaretPosition = " + lastCaretPosition);
//                    System.out.println("caretPosition = " + caretPosition);
//                    System.out.println("diffRemLetter = " + diffRemLetter);
//                    if ((lastCaretPosition == caretPosition || lastCaretPosition == (caretPosition - diffRemLetter)) && diffRemLetter > 1) {
//                        tf.positionCaret(caretPosition - diffRemLetter);
//                        System.out.println("r1");
//                    } else {
//                        System.out.println("caretPosition + diffRemLetter = " + (caretPosition - diffRemLetter));
////                        System.out.println("(newValue.substring(0, caretPosition) = " + (newValue.substring(0, caretPosition)));
//                        System.out.println("oldValue.substring(0, caretPosition) = " + oldValue.substring(0, caretPosition));
////                        System.out.println("newValue.substring(caretPosition) = " + newValue.substring(caretPosition +1));
//                        System.out.println("caretPosition = " + caretPosition);
//                        if (newValue.length() > caretPosition) {
//                            if (newValue.substring(0, caretPosition).equals(oldValue.substring(0, caretPosition)) && oldValue.endsWith(newValue.substring(caretPosition + 1)) && !"".equals(newValue.substring(caretPosition + 1)) && !String.valueOf(newValue.charAt(caretPosition - 1)).equals(separator)) {
//                                tf.positionCaret(caretPosition);
//                                System.out.println("r2");
//                            } else if (Character.isDigit(newValue.charAt(caretPosition - 1)) && Character.isDigit(newValue.charAt(caretPosition)) && diffRemLetter == 1) {
//                                tf.positionCaret(caretPosition);
//                                System.out.println("r5");
//                            } else {
//                                tf.positionCaret(caretPosition + 1);
//                                System.out.println("r3");
//                            }
//                        } else {
//                            System.out.println("r4");
//                            tf.positionCaret(lastCaretPosition);
//                        }
//                        last = oldValue;
//                    }
//                } else if (String.valueOf(resultat.charAt(caretPosition - 1)).equals(separator) && last.length() < resultat.length()) {
//                    tf.positionCaret(caretPosition + 1);
//                    System.out.println("s");
//                } else {
//                    tf.positionCaret(caretPosition);
//                    System.out.println("o");
//                }
//                if (resultat.length() >= caretPosition) {
//                    if (oldValue.replaceAll(separator, "").equals(newValue.replaceAll(separator, "")) && String.valueOf(resultat.charAt(caretPosition)).equals(separator)) {
//                        tf.positionCaret(caretPosition);
//                        System.out.println("c");
//                    }
//                }
//                lastCaretPosition = caretPosition;
            } else {
                textPropertyFromComponent.set(oldValue);
            }
        });
        textPropertyFromComponent.addListener(updateText);
    }

//Method to format the phone number
    private String getPhoneNumberFormatted(String phoneNumber, String format) {
        textPropertyFromComponent.removeListener(updateText);
        String vretour = "";
        if (phoneNumber.length() <= format.length()) {
            phoneNumber = phoneNumber.replaceAll("[^0-9+]", "");
            int index = findXDotPosition(format, phoneNumber.length());
            format = format.substring(0, index + 1);
            int indexCharArray = 0;
            for (char unChar : format.toCharArray()) {
                if ("#".charAt(0) == unChar) {
                    vretour = vretour + phoneNumber.toCharArray()[indexCharArray];
                    indexCharArray++;
                }
                if ("-".charAt(0) == unChar) {
                    vretour = vretour + separator;
                }
            }
        } else {
            vretour = phoneNumber;
        }
        return vretour;
    }

//Method to find a separator
    private static int findXDotPosition(String s, int separatorToFind) {
        int result = -1;
        char[] ca = s.toCharArray();
        for (int i = 0; i < ca.length; ++i) {
            if (ca[i] == '#') {
                --separatorToFind;
            }
            if (separatorToFind == 0) {
                return i;
            }
        }
        return result;
    }
}

I also provide you some screenshots of the actual working of the application.

https://i.goopics.net/Jl8aR.png https://i.goopics.net/RVvdZ.png

Hoping you can offer me a solution, Thanks in advance !

Spinogl
  • 15
  • 6
  • 1
    use a TextFormatter instead of a listener – kleopatra Jun 03 '21 at 08:45
  • I quickly tried it but never used it and didn't fully understand how to use it. Wouldn't you have an example? – Spinogl Jun 03 '21 at 08:52
  • do a bit of research, there are tons of examples (on this site mostly around number input, but the approach is exactly the same) – kleopatra Jun 03 '21 at 09:05
  • The duplicate [Numeric TextField for Integers in JavaFX 8 with TextFormatter and/or UnaryOperator](https://stackoverflow.com/questions/40472668/numeric-textfield-for-integers-in-javafx-8-with-textformatter-and-or-unaryoperat) has a nice example, including changing caret location – kleopatra Jun 03 '21 at 09:14
  • I will look into this thank you very much – Spinogl Jun 03 '21 at 09:27
  • It seems that this is not what I am looking for. Indeed, this person wants the changes to be made when he leaves the field, but I would like it to be totally automatic, in real time and without having to leave the field. Or maybe I didn't understand the other post (I quote: "So I am at a loss. I essentially want to allow only digits and then when the user leaves the field present the value in a formatted way - without actually changing the string value that goes to the database.") – Spinogl Jun 03 '21 at 09:35
  • you don't to leave the field - you can change whatever you want, a textFormatter gives you complete control about everything: move the caret (or not) as you need it. – kleopatra Jun 03 '21 at 09:56
  • You should hide the name of your company in the first line (`package com...`) because I'm not sure this is completely legal – 0009laH Jun 04 '21 at 08:09
  • My company is ok to do that, but yes, it's better without – Spinogl Jun 04 '21 at 08:16

2 Answers2

0

TextFormatter is definitely the way to go. What you need to build is the filter component for the TextFormatter. Basically, you can think of this as a keystroke processor (that handles mouse actions as well), where all of the low-level stuff has been handled for you. You get a TextFormatter.Change object passed to you, and you can see how that change will impact the value in the field, and then modify it, suppress it, or let it pass through.

So all of the formatting happens instantly, right in the TextField as you type.

I built one to handle North American style phone numbers, because it's a little more interesting than the European style since it has brackets and dashes. But you can adapt it.

The approach I took was to strip all of the formatting characters out of the string, then reformat it from scratch each time a change was made. This seems easier than trying to fiddle with it character by character. The only tricky part was hitting <BackSpace> over a "-" or ")", where I assumed that you'd want to delete the number in front of the special character. It might make more sense to just move the caret to the left of the special character:

public class PhoneNumberFilter implements UnaryOperator<TextFormatter.Change> {

@Override
public TextFormatter.Change apply(TextFormatter.Change change) {
    if (change.isContentChange()) {
        handleBackspaceOverSpecialCharacter(change);
        if (change.getText().matches("[0-9]*")) {
            int originalNewTextLength = change.getControlNewText().length();
            change.setText(formatNumber(change.getControlNewText()));
            change.setRange(0, change.getControlText().length());
            int caretOffset = change.getControlNewText().length() - originalNewTextLength;
            change.setCaretPosition(change.getCaretPosition() + caretOffset);
            change.setAnchor(change.getAnchor() + caretOffset);
            return change;
        } else {
            return null;
        }
    }
    return change;
}

private void handleBackspaceOverSpecialCharacter(TextFormatter.Change change) {
    if (change.isDeleted() && (change.getSelection().getLength() == 0)) {
        if (!Character.isDigit(change.getControlText().charAt(change.getRangeStart()))) {
            if (change.getRangeStart() > 0) {
                change.setRange(change.getRangeStart() - 1, change.getRangeEnd() - 1);
            }
        }
    }
}

private String formatNumber(String numbers) {
    numbers = numbers.replaceAll("[^\\d]", "");
    numbers = numbers.substring(0, Math.min(10, numbers.length()));
    if (numbers.length() == 0) {
        return "";
    }
    if (numbers.length() < 4) {
        return "(" + numbers;
    }
    if (numbers.length() < 7) {
        return numbers.replaceFirst("(\\d{3})(\\d+)", "($1)$2");
    }
    return numbers.replaceFirst("(\\d{3})(\\d{3})(\\d+)", "($1)$2-$3");
}

}

Here's a little test application. You can see that the converter is just the "out of the box" default converter, since it's just a string composed of mostly numbers:

public class PhoneNumberTest extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        TextField textField = new TextField();
        TextFormatter<String> textFormatter = new TextFormatter(new DefaultStringConverter(), "", new PhoneNumberFilter());
        textField.setTextFormatter(textFormatter);
        Scene scene = new Scene(new VBox(textField), 300, 100);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
DaveB
  • 1,836
  • 1
  • 15
  • 13
0

Thanks a lot for your answer DaveB! It works perfectly well, I provide you the final code :

package PhoneNumberTest;

import java.util.function.UnaryOperator;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.util.converter.DefaultStringConverter;
import org.apache.commons.lang3.StringUtils;

public class PhoneNumberFilter implements UnaryOperator<TextFormatter.Change> {

    private String separator = " ";
    private int length = 0;
    private TextField tf;

    private final String formatForFrance = "###-#-##-##-##-##";
    private final String formatForAllemagne = "###-###-###-##-###";
    private final String formatForEspagne = "###-###-##-##-##";
    private final String formatForBelgiqueGSM = "###-###-##-##-##";
    private final String formatForBelgiqueAutre = "###-#-###-##-##";
    private final String formatForBelgique = "###-##-##-##-##";
    private final String formatForLuxembourg = "####-###-###-###";
    private final String formatForLuxembourgAutre = "####-##-##-##-##";
    private final String formatForMonaco = "####-##-##-##-##";
    private final String formatForSuisse = "###-##-###-##-##";
    private final String formatForItalieFixe = "###-##-####-####";
    private final String formatForItaliePort = "###-###-###-####";
    private final String formatForItalieAutre = "###-##-####-####";
    private final String formatForAndorre = "####-###-###-###";
    private final String formatForGuadeloupe = "####-###-##-##-##";
    private final String formatForMartinique = "####-###-##-##-##";
    private final String formatForGuyane = "####-###-##-##-##";
    private final String formatForReunionMayotte = "####-###-##-##-##";
    private final String formatForNouvelleCaledonie = "####-##-##-##";
    private final String formatForAutre = "######################";
    private final String formatForFranceNationnal = "##-##-##-##-##";

    public PhoneNumberFilter(TextField textField, String separator) {
        this.tf = textField;
        if (separator != null && !separator.isEmpty()) {
            this.separator = separator;
        } else {
            this.separator = "";
        }
        TextFormatter<String> textFormatter = new TextFormatter(new DefaultStringConverter(), "", new PhoneNumberFilter());
        tf.setTextFormatter(textFormatter);
    }

    public PhoneNumberFilter() {
    }

    @Override
    public TextFormatter.Change apply(TextFormatter.Change change) {
        if (change.isContentChange()) {
            String resultat = "";
            handleBackspaceOverSpecialCharacter(change);
            int originalNewTextLength = change.getControlNewText().length();
            if (change.getControlNewText().startsWith("+33")) {
//            System.out.println("FRANCE");
                length = formatForFrance.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForFrance);
            } else if (change.getControlNewText().startsWith("+49")) {
//            System.out.println("ALLEMAGNE");
                length = formatForAllemagne.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForAllemagne);
            } else if (change.getControlNewText().startsWith("+34")) {
//            System.out.println("ESPAGNE");
                length = formatForEspagne.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForEspagne);
            } else if (change.getControlNewText().replaceAll(separator, "").startsWith("+3245") || change.getControlNewText().replaceAll(separator, "").startsWith("+3249")) {
//            System.out.println("BELGIQUE GSM");
                length = formatForBelgiqueGSM.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForBelgiqueGSM);
            } else if (change.getControlNewText().replaceAll(separator, "").startsWith("+322") || change.getControlNewText().replaceAll(separator, "").startsWith("+323") || change.getControlNewText().replaceAll(separator, "").startsWith("+329")) {
//            System.out.println("BELGIQUE AUTRE 1");
                length = formatForBelgiqueAutre.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForBelgiqueAutre);
            } else if (change.getControlNewText().startsWith("+32")) {
//            System.out.println("BELGIQUE");
                length = formatForBelgique.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForBelgique);
            } else if (change.getControlNewText().replaceAll(separator, "").startsWith("+3526")) {
//            System.out.println("LUXEMBOURG 1");
                length = formatForLuxembourg.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForLuxembourg);
            } else if (change.getControlNewText().startsWith("+352")) {
//            System.out.println("LUXEMBOURG AUTRE");
                length = formatForLuxembourgAutre.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForLuxembourgAutre);
            } else if (change.getControlNewText().startsWith("+377")) {
//            System.out.println("MONACO");
                length = formatForMonaco.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForMonaco);
            } else if (change.getControlNewText().startsWith("+41")) {
//            System.out.println("SUISSE");
                length = formatForSuisse.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForSuisse);
            } else if (change.getControlNewText().replaceAll(separator, "").startsWith("+390")) {
//            System.out.println("ITALIE FIXE");
                length = formatForItalieFixe.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForItalieFixe);
            } else if (change.getControlNewText().replaceAll(separator, "").startsWith("+393")) {
//            System.out.println("ITALIE PORTABLE");
                length = formatForItaliePort.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForItaliePort);
            } else if (change.getControlNewText().startsWith("+39")) {
//            System.out.println("ITALIE AUTRE");
                length = formatForItalieAutre.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForItalieAutre);
            } else if (change.getControlNewText().startsWith("+376")) {
//            System.out.println("ANDORRE");
                length = formatForAndorre.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForAndorre);
            } else if (change.getControlNewText().startsWith("+590")) {
//            System.out.println("GUADELOUPE");
                length = formatForGuadeloupe.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForGuadeloupe);
            } else if (change.getControlNewText().startsWith("+596")) {
//            System.out.println("MARTINIQUE");
                length = formatForMartinique.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForMartinique);
            } else if (change.getControlNewText().startsWith("+594")) {
//            System.out.println("GUYANE");
                length = formatForGuyane.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForGuyane);
            } else if (change.getControlNewText().startsWith("+262")) {
//            System.out.println("REUNION ET MAYOTTE");
                length = formatForReunionMayotte.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForReunionMayotte);
            } else if (change.getControlNewText().startsWith("+687")) {
//            System.out.println("NOUVELLE-CALEDONIE");
                length = formatForNouvelleCaledonie.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForNouvelleCaledonie);
            } else if (change.getControlNewText().startsWith("+")) {
//            System.out.println("AUTRE - PAYS NON REFERENCE");
                length = formatForAutre.length();
                resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForAutre);
            } else if (change.getControlNewText().length() >= 3) {
                if (Character.isDigit(change.getControlNewText().charAt(0))) {
//                System.out.println("France Nationnal");
                    length = formatForFranceNationnal.length();
                    resultat = getPhoneNumberFormatted(change.getControlNewText(), formatForFranceNationnal);
                }
            } else {
                resultat = change.getControlNewText();
            }
            if (change.getControlText().length() == length && originalNewTextLength > length && length != 0) {
                change.setText(change.getControlText());
            } else {
                change.setText(resultat);
            }
            change.setRange(0, change.getControlText().length());
            int caretOffset = change.getControlNewText().length() - originalNewTextLength;
            change.setCaretPosition(change.getCaretPosition() + caretOffset);
            change.setAnchor(change.getAnchor() + caretOffset);
            return change;
        }
        return change;
    }

    private void handleBackspaceOverSpecialCharacter(TextFormatter.Change change) {
        if (change.isDeleted() && (change.getSelection().getLength() == 0)) {
            if (!Character.isDigit(change.getControlText().charAt(change.getRangeStart())) && !"+".equals(String.valueOf(change.getControlText().charAt(change.getRangeStart())))) {
                if (change.getRangeStart() > 0) {
                    change.setRange(change.getRangeStart() - 1, change.getRangeEnd() - 1);
                }
            }
        }
    }

    private String getPhoneNumberFormatted(String phoneNumber, String format) {
        if (phoneNumber.length() > length) {
            phoneNumber = phoneNumber.substring(0, length);
        }
        String vretour = "";
        if (phoneNumber.length() <= format.length()) {
            phoneNumber = phoneNumber.replaceAll("[^0-9+]", "");
            int index = findXDotPosition(format, phoneNumber.length());
            format = format.substring(0, index + 1);
            int indexCharArray = 0;
            for (char unChar : format.toCharArray()) {
                if ("#".charAt(0) == unChar) {
                    vretour = vretour + phoneNumber.toCharArray()[indexCharArray];
                    indexCharArray++;
                }
                if ("-".charAt(0) == unChar) {
                    vretour = vretour + separator;
                }
            }
        } else {
            vretour = phoneNumber;
        }
        return vretour;
    }

    private static int findXDotPosition(String s, int separatorToFind) {
        int result = -1;
        char[] ca = s.toCharArray();
        for (int i = 0; i < ca.length; ++i) {
            if (ca[i] == '#') {
                --separatorToFind;
            }
            if (separatorToFind == 0) {
                return i;
            }
        }
        return result;
    }
}

Just create an object like this new PhoneNumberFilter(tf, " "); (tf = TextField and the second parameter is the separator between the different phone numbers). This will execute the rest of the program and will reformat the entered numbers perfectly well.

I just have one last question. When I click at the end of the phone number twice, or when I try to write at the very end when the number is already the maximum number of characters indicated, my cursor moves back 1 notch for no apparent reason and I can't find a way to force the cursor to stay at the very end of the number. Is this normal? Is there a solution ?

Spinogl
  • 15
  • 6