Jaki jest zalecany sposób tworzenia numerycznego pola tekstowego w JavaFX?


85

Muszę ograniczyć dane wejściowe do TextField do liczb całkowitych. Jakakolwiek rada?


3
Uwaga: odsłuchiwanie właściwości textProperty jest błędne ! To było najlepsze, co można było zrobić przed utworzeniem TextFormattera (od fx8u40 lub czegoś podobnego). Od tego czasu obowiązuje podstawowa zasada: ogólnie modyfikowanie obserwowanej wartości w tej metodzie jest uważane za złą praktykę, a użycie TextFormatter jest jedynym akceptowalnym rozwiązaniem.
kleopatra

Odpowiedzi:


118

Bardzo stary wątek, ale wydaje się schludniejszy i po wklejeniu usuwa znaki nienumeryczne.

// force the field to be numeric only
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, 
        String newValue) {
        if (!newValue.matches("\\d*")) {
            textField.setText(newValue.replaceAll("[^\\d]", ""));
        }
    }
});

3
Działa wspaniale. Zauważ, że możesz także użyć \\D+(lub po prostu \\D) zamiast [^\\d], jeśli chcesz zaoszczędzić kilka znaków.
ricky3350

5
Jeszcze prostsze jest ustawienie tekstu z powrotem na oldValue. W ten sposób nie musisz majstrować przy zamianach wyrażeń regularnych (co niestety w ogóle nie działało).
geisterfurz007

@ geisterfurz007 Daje to jednak możliwość usunięcia wartości nienumerycznych z wklejonego tekstu.
Evan Knowles,

10
Nieaktualny, zobacz odpowiedź TextFormatter poniżej.
gerardw

3
Może też po prostu użyć Integer.parseInt(newValue)i użyć tryi catchwykryć błąd naNumberFormatException
Pixel

43

Aktualizacja kwiecień 2016 r

Ta odpowiedź powstała kilka lat temu, a pierwotna odpowiedź jest obecnie w dużej mierze przestarzała.

Od wersji Java 8u40 Java ma TextFormatter, który zwykle najlepiej nadaje się do wymuszania wprowadzania określonych formatów, takich jak liczby, w polach tekstowych JavaFX:

Zobacz także inne odpowiedzi na to pytanie, które wyraźnie wspominają o TextFormatter.


Oryginalna odpowiedź

W tym tekście jest kilka przykładów , powieliłem jeden z poniższych przykładów:

// helper text field subclass which restricts text input to a given range of natural int numbers
// and exposes the current numeric int value of the edit box as a value property.
class IntField extends TextField {
  final private IntegerProperty value;
  final private int minValue;
  final private int maxValue;

  // expose an integer value property for the text field.
  public int  getValue()                 { return value.getValue(); }
  public void setValue(int newValue)     { value.setValue(newValue); }
  public IntegerProperty valueProperty() { return value; }

  IntField(int minValue, int maxValue, int initialValue) {
    if (minValue > maxValue) 
      throw new IllegalArgumentException(
        "IntField min value " + minValue + " greater than max value " + maxValue
      );
    if (maxValue < minValue) 
      throw new IllegalArgumentException(
        "IntField max value " + minValue + " less than min value " + maxValue
      );
    if (!((minValue <= initialValue) && (initialValue <= maxValue))) 
      throw new IllegalArgumentException(
        "IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue
      );

    // initialize the field values.
    this.minValue = minValue;
    this.maxValue = maxValue;
    value = new SimpleIntegerProperty(initialValue);
    setText(initialValue + "");

    final IntField intField = this;

    // make sure the value property is clamped to the required range
    // and update the field's text to be in sync with the value.
    value.addListener(new ChangeListener<Number>() {
      @Override public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
        if (newValue == null) {
          intField.setText("");
        } else {
          if (newValue.intValue() < intField.minValue) {
            value.setValue(intField.minValue);
            return;
          }

          if (newValue.intValue() > intField.maxValue) {
            value.setValue(intField.maxValue);
            return;
          }

          if (newValue.intValue() == 0 && (textProperty().get() == null || "".equals(textProperty().get()))) {
            // no action required, text property is already blank, we don't need to set it to 0.
          } else {
            intField.setText(newValue.toString());
          }
        }
      }
    });

    // restrict key input to numerals.
    this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
      @Override public void handle(KeyEvent keyEvent) {
        if(intField.minValue<0) {
                if (!"-0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();
                }
            }
            else {
                if (!"0123456789".contains(keyEvent.getCharacter())) {
                    keyEvent.consume();
                }
            }
      }
    });

    // ensure any entered values lie inside the required range.
    this.textProperty().addListener(new ChangeListener<String>() {
      @Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
        if (newValue == null || "".equals(newValue) || (intField.minValue<0 && "-".equals(newValue))) {
          value.setValue(0);
          return;
        }

        final int intValue = Integer.parseInt(newValue);

        if (intField.minValue > intValue || intValue > intField.maxValue) {
          textProperty().setValue(oldValue);
        }

        value.set(Integer.parseInt(textProperty().get()));
      }
    });
  }
}

42

Wiem, że to dość stary wątek, ale dla przyszłych czytelników jest tutaj inne rozwiązanie, które uznałem za dość intuicyjne:

public class NumberTextField extends TextField
{

    @Override
    public void replaceText(int start, int end, String text)
    {
        if (validate(text))
        {
            super.replaceText(start, end, text);
        }
    }

    @Override
    public void replaceSelection(String text)
    {
        if (validate(text))
        {
            super.replaceSelection(text);
        }
    }

    private boolean validate(String text)
    {
        return text.matches("[0-9]*");
    }
}

Edycja: dziękuję none_ i SCBoy za sugerowane ulepszenia.


1
Czy ktoś wie, jakiego wyrażenia regularnego użyć dla liczb dziesiętnych (np. 123.456)? Wartość parametru funkcji validate (tekst) „tekst” jest ostatnim znakiem edytowanym przez użytkownika, a nie całym ciągiem znaków w polu tekstowym, dlatego wyrażenie regularne może nie być poprawnie dopasowane. Na przykład używam tego polecenia w ten sposób: text.matches("\\d+"); i nie mogę usunąć żadnych znaków z pola tekstowego
mils

1
@mils Spójrz tutaj i tutaj .
vellotis

1
Myślę, że to dobre rozwiązanie, ale jedną rzecz bym zmienił. Zamiast pisać text.matches ("[0-9] *") stworzyłbym zmienną dla wzorca i skompilowałbym ją. W twoim kodzie wzorzec jest kompilowany za każdym razem, gdy ktoś pisze znak w polu, a to jest kosztowne dla procesora i pamięci. Więc dodałbym zmienną: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); I zamień treść walidacji na: integerPattern.matcher (tekst) .matches ();
P. Jowko

38

Począwszy od JavaFX 8u40, można ustawić obiekt TextFormatter w polu tekstowym:

UnaryOperator<Change> filter = change -> {
    String text = change.getText();

    if (text.matches("[0-9]*")) {
        return change;
    }

    return null;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
fieldNport = new TextField();
fieldNport.setTextFormatter(textFormatter);

Pozwala to uniknąć podklas i zduplikowanych zdarzeń zmiany, które otrzymasz, gdy dodasz odbiornik zmian do właściwości text i zmodyfikujesz tekst w tym detektorze.


30

TextInputMa TextFormatterktóre mogą być wykorzystane do formatu, konwersji i ograniczyć rodzaje tekstów, które mogą być wprowadzane.

TextFormatterPosiada filtr, który może być stosowany do odrzucenia wejście. Musimy ustawić tę opcję, aby odrzucić wszystko, co nie jest prawidłową liczbą całkowitą. Posiada również konwerter, który musimy ustawić, aby przekonwertować wartość ciągu na wartość całkowitą, którą możemy później powiązać.

Utwórzmy filtr wielokrotnego użytku:

public class IntegerFilter implements UnaryOperator<TextFormatter.Change> {
    private final static Pattern DIGIT_PATTERN = Pattern.compile("\\d*");

    @Override
    public Change apply(TextFormatter.Change aT) {
        return DIGIT_PATTERN.matcher(aT.getText()).matches() ? aT : null;
    }
}

Filtr może zrobić jedną z trzech rzeczy, może zwrócić niezmodyfikowaną zmianę, aby zaakceptować ją taką, jaka jest, może zmienić zmianę w sposób, który uzna za stosowny, lub może powrócić, nullaby odrzucić zmianę w całości.

Użyjemy standardu IntegerStringConverterjako konwertera.

Łącząc to wszystko mamy:

TextField textField = ...;

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), // Standard converter form JavaFX
    defaultValue, 
    new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);

textField.setTextFormatter(formatter);

Jeśli nie chcesz, nie potrzebujesz filtra wielokrotnego użytku, możesz zamiast tego zrobić ten fantazyjny jednolinijkowy:

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), 
    defaultValue,  
    c -> Pattern.matches("\\d*", c.getText()) ? c : null );

21

Nie lubię wyjątków, dlatego użyłem matchesfunkcji z String-Class

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, 
        String newValue) {
        if (newValue.matches("\\d*")) {
            int value = Integer.parseInt(newValue);
        } else {
            text.setText(oldValue);
        }
    }
});

1
czasami masz wyjątek, ponieważ liczba może być zbyt duża.
schlagi123

1
Wskazówka: zamień wyrażenie regularne „\\ d +” na „\\ d *”. Umożliwi to usunięcie wszystkich znaków z pola wprowadzania tekstu (użyj klawisza Backspace / Delete, aby wyczyścić pole).
Guus,

1
Nie zapomnij ustawić pozycji karetki po przywróceniu jej starej wartości:textField.positionCaret(textField.getLength());
hsson

Zmień pierwszy warunek if na: if (newValue.matches("\\d*") && newValue.getText().length < 5) jeśli chcesz w tym przypadku ograniczyć dane wejściowe do 4 cyfr.
Cappuccino90

@ Cappuccino90 Powinieneś zmienić instrukcje, ponieważ sprawdzanie długości jest znacznie tańsze przy każdym trafieniu niż analizowanie wyrażenia regularnego
znaczy,

9

Począwszy od Java SE 8u40 , w takiej sytuacji można użyć „ liczby całkowitej ”, która Spinnerpozwala bezpiecznie wybrać prawidłową liczbę całkowitą za pomocą klawiszy strzałek w górę / w dół lub strzałek w górę / w dół na klawiaturze.

Można również zdefiniować wartość minimalną , maksymalną i początkową, aby ograniczyć dozwolone wartości i kwotę, o którą można zwiększać lub zmniejszać, na krok.

Na przykład

// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value
Spinner<Integer> spinner1 = new Spinner<>(1, 10, 2);
// Creates an integer spinner with 0 as min, 100 as max and 10 as initial 
// value and 10 as amount to increment or decrement by, per step
Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);

Przykład wyniku z pokrętłem „ integer ” i „ podwójnym ” pokrętłem

wprowadź opis obrazu tutaj

Spinner jest tekst kontrola pole single-linia, która pozwala użytkownikowi wybrać liczbę lub wartość obiektu z uporządkowanej sekwencji takich wartości. Pokrętła zazwyczaj zapewniają parę małych przycisków ze strzałkami do przechodzenia między elementami sekwencji. Klawisze strzałek w górę / w dół na klawiaturze również przełączają elementy. Użytkownik może również mieć możliwość wpisania (dozwolonej) wartości bezpośrednio do pokrętła. Chociaż pola kombi zapewniają podobną funkcjonalność, czasami preferowane są pokrętła, ponieważ nie wymagają rozwijanej listy, która może zasłaniać ważne dane, a także dlatego, że pozwalają na takie funkcje, jak zawijanie od wartości maksymalnej do minimalnej (np. od największej dodatniej liczby całkowitej do 0).

Więcej szczegółów na temat formantu Spinner


Ludzie nie powinni, aby spinner nie sprawdzał poprawności podczas wprowadzania tekstu lub stracił koncentrację
geometrikal

7

Preferowana odpowiedź może być jeszcze mniejsza, jeśli używasz Java 1.8 Lambdas

textfield.textProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue.matches("\\d*")) return;
    textfield.setText(newValue.replaceAll("[^\\d]", ""));
});

6
TextField text = new TextField();

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable,
            String oldValue, String newValue) {
        try {
            Integer.parseInt(newValue);
            if (newValue.endsWith("f") || newValue.endsWith("d")) {
                manualPriceInput.setText(newValue.substring(0, newValue.length()-1));
            }
        } catch (ParseException e) {
            text.setText(oldValue);
        }
    }
});

ifKlauzula jest ważne, aby wejść rączki jak 0,5 D lub 0.7f, które są prawidłowo przetwarzane przez Int.parseInt (), ale nie powinien pojawić się w polu tekstowym.


9
Co? Od kiedy 0.5d jest poprawnie analizowane przez Integer.parseInt () ?! Wyrzuca wyjątek java.lang.NumberFormatException: Dla ciągu wejściowego: „0.5d” (zgodnie z oczekiwaniami, ponieważ nie jest to liczba całkowita)
Burkhard

4

Wypróbuj ten prosty kod, który wykona zadanie.

DecimalFormat format = new DecimalFormat( "#.0" );
TextField field = new TextField();
field.setTextFormatter( new TextFormatter<>(c ->
{
    if ( c.getControlNewText().isEmpty() )
    {
        return c;
    }

    ParsePosition parsePosition = new ParsePosition( 0 );
    Object object = format.parse( c.getControlNewText(), parsePosition );

    if ( object == null || parsePosition.getIndex() <          c.getControlNewText().length() )
    {
        return null;
    }
    else
    {
        return c;
    }
}));

3

Jeśli chcesz zastosować ten sam detektor do więcej niż jednego pola TextField, oto najprostsze rozwiązanie:

TextField txtMinPrice, txtMaxPrice = new TextField();

ChangeListener<String> forceNumberListener = (observable, oldValue, newValue) -> {
    if (!newValue.matches("\\d*"))
      ((StringProperty) observable).set(oldValue);
};

txtMinPrice.textProperty().addListener(forceNumberListener);
txtMaxPrice.textProperty().addListener(forceNumberListener);

3

Ten pracował dla mnie.

public void RestrictNumbersOnly(TextField tf){
    tf.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> observable, String oldValue, 
            String newValue) {
            if (!newValue.matches("|[-\\+]?|[-\\+]?\\d+\\.?|[-\\+]?\\d+\\.?\\d+")){
                tf.setText(oldValue);
            }
        }
    });
}

3

Chcę pomóc w moim pomyśle, łącząc odpowiedź Evan Knowles z TextFormatterz JavaFX 8

textField.setTextFormatter(new TextFormatter<>(c -> {
    if (!c.getControlNewText().matches("\\d*")) 
        return null;
    else
        return c;
    }
));

więc powodzenia;) zachowaj spokój i koduj java


2

Oto prosta klasa, która obsługuje podstawowe walidacje TextField, używając TextFormatterwprowadzonych w JavaFX 8u40

EDYTOWAĆ:

(Kod dodany do komentarza Floern)

import java.text.DecimalFormatSymbols;
import java.util.regex.Pattern;

import javafx.beans.NamedArg;
import javafx.scene.control.TextFormatter;
import javafx.scene.control.TextFormatter.Change;

public class TextFieldValidator {

    private static final String CURRENCY_SYMBOL   = DecimalFormatSymbols.getInstance().getCurrencySymbol();
    private static final char   DECIMAL_SEPARATOR = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    private final Pattern       INPUT_PATTERN;

    public TextFieldValidator(@NamedArg("modus") ValidationModus modus, @NamedArg("countOf") int countOf) {
        this(modus.createPattern(countOf));
    }

    public TextFieldValidator(@NamedArg("regex") String regex) {
        this(Pattern.compile(regex));
    }

    public TextFieldValidator(Pattern inputPattern) {
        INPUT_PATTERN = inputPattern;
    }

    public static TextFieldValidator maxFractionDigits(int countOf) {
        return new TextFieldValidator(maxFractionPattern(countOf));
    }

    public static TextFieldValidator maxIntegers(int countOf) {
        return new TextFieldValidator(maxIntegerPattern(countOf));
    }

    public static TextFieldValidator integersOnly() {
        return new TextFieldValidator(integersOnlyPattern());
    }

    public TextFormatter<Object> getFormatter() {
        return new TextFormatter<>(this::validateChange);
    }

    private Change validateChange(Change c) {
        if (validate(c.getControlNewText())) {
            return c;
        }
        return null;
    }

    public boolean validate(String input) {
        return INPUT_PATTERN.matcher(input).matches();
    }

    private static Pattern maxFractionPattern(int countOf) {
        return Pattern.compile("\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?");
    }

    private static Pattern maxCurrencyFractionPattern(int countOf) {
        return Pattern.compile("^\\" + CURRENCY_SYMBOL + "?\\s?\\d*(\\" + DECIMAL_SEPARATOR + "\\d{0," + countOf + "})?\\s?\\" +
                CURRENCY_SYMBOL + "?");
    }

    private static Pattern maxIntegerPattern(int countOf) {
        return Pattern.compile("\\d{0," + countOf + "}");
    }

    private static Pattern integersOnlyPattern() {
        return Pattern.compile("\\d*");
    }

    public enum ValidationModus {

        MAX_CURRENCY_FRACTION_DIGITS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxCurrencyFractionPattern(countOf);
            }
        },

        MAX_FRACTION_DIGITS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxFractionPattern(countOf);
            }
        },
        MAX_INTEGERS {
            @Override
            public Pattern createPattern(int countOf) {
                return maxIntegerPattern(countOf);
            }
        },

        INTEGERS_ONLY {
            @Override
            public Pattern createPattern(int countOf) {
                return integersOnlyPattern();
            }
        };

        public abstract Pattern createPattern(int countOf);
    }

}

Możesz go używać w ten sposób:

textField.setTextFormatter(new TextFieldValidator(ValidationModus.INTEGERS_ONLY).getFormatter());

lub możesz utworzyć instancję w pliku fxml i zastosować ją do customTextField z odpowiednimi właściwościami.

app.fxml:

<fx:define>
    <TextFieldValidator fx:id="validator" modus="INTEGERS_ONLY"/>
</fx:define>

CustomTextField.class:

public class CustomTextField {

private TextField textField;

public CustomTextField(@NamedArg("validator") TextFieldValidator validator) {
        this();
        textField.setTextFormatter(validator.getFormatter());
    }
}

Kod na githubie


2

Oto czego używam:

private TextField textField;
textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        if(!newValue.matches("[0-9]*")){
            textField.setText(oldValue);
        }

    }
});

To samo w notacji lambda wyglądałoby tak:

private TextField textField;
textField.textProperty().addListener((observable, oldValue, newValue) -> {
    if(!newValue.matches("[0-9]*")){
        textField.setText(oldValue);
    }
});

2

Ta metoda umożliwia TextField zakończenie całego przetwarzania (bezpieczne kopiowanie / wklejanie / cofanie). Nie wymaga rozszerzania klas i pozwala zdecydować, co zrobić z nowym tekstem po każdej zmianie (aby wypchnąć go do logiki, wrócić do poprzedniej wartości, a nawet zmodyfikować).

  // fired by every text property change
textField.textProperty().addListener(
  (observable, oldValue, newValue) -> {
    // Your validation rules, anything you like
      // (! note 1 !) make sure that empty string (newValue.equals("")) 
      //   or initial text is always valid
      //   to prevent inifinity cycle
    // do whatever you want with newValue

    // If newValue is not valid for your rules
    ((StringProperty)observable).setValue(oldValue);
      // (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))
      //   to anything in your code.  TextProperty implementation
      //   of StringProperty in TextFieldControl
      //   will throw RuntimeException in this case on setValue(string) call.
      //   Or catch and handle this exception.

    // If you want to change something in text
      // When it is valid for you with some changes that can be automated.
      // For example change it to upper case
    ((StringProperty)observable).setValue(newValue.toUpperCase());
  }
);

W twoim przypadku po prostu dodaj tę logikę do środka. Działa świetnie.

   if (newValue.equals("")) return; 
   try {
     Integer i = Integer.valueOf(newValue);
     // do what you want with this i
   } catch (Exception e) {
     ((StringProperty)observable).setValue(oldValue);
   }

0

Mmmm. Napotkałem ten problem kilka tygodni temu. Ponieważ interfejs API nie zapewnia kontroli, aby to osiągnąć,
możesz użyć własnego.
Użyłem czegoś takiego:

public class IntegerBox extends TextBox {
    public-init var value : Integer = 0;
    protected function apply() {
        try {
            value = Integer.parseInt(text);
        } catch (e : NumberFormatException) {}
        text = "{value}";
    }
    override var focused = false on replace {apply()};
    override var action = function () {apply()}
}

Jest używany w taki sam sposób, jak normalny TextBox,
ale ma również valueatrybut, który przechowuje wprowadzoną liczbę całkowitą.
Gdy formant traci fokus, sprawdza poprawność wartości i przywraca ją (jeśli nie jest poprawna).


2
jaki to język?
Stealth Rabbi

To rabin JavaFX Script , jest przestarzały .
jewelsea

0

ten kod Stwórz swój textField Zaakceptuj tylko numer

textField.lengthProperty().addListener((observable, oldValue, newValue) -> {
        if(newValue.intValue() > oldValue.intValue()){
            char c = textField.getText().charAt(oldValue.intValue());
            /** Check if the new character is the number or other's */
            if( c > '9' || c < '0'){
                /** if it's not number then just setText to previous one */
                textField.setText(textField.getText().substring(0,textField.getText().length()-1));
            }
        }
    });

0

Ten kod działa dobrze, nawet jeśli spróbujesz skopiować / wkleić.

myTextField.textProperty().addListener((observable, oldValue, newValue) -> {
    if (!newValue.matches("\\d*")) {
        myTextField.setText(oldValue);

    }
});

-1

W ostatnich aktualizacjach JavaFX musisz ustawić nowy tekst w metodzie Platform.runLater, tak jak poniżej:

    private void set_normal_number(TextField textField, String oldValue, String newValue) {
    try {
        int p = textField.getCaretPosition();
        if (!newValue.matches("\\d*")) {
            Platform.runLater(() -> {
                textField.setText(newValue.replaceAll("[^\\d]", ""));
                textField.positionCaret(p);
            });
        }
    } catch (Exception e) {
    }
}

Dobrym pomysłem jest również ustawienie pozycji karetki.


1
Dziękuję za Twoją odpowiedź! Czy mógłbyś trochę wyjaśnić, dlaczego Platform.runLaterjest potrzebny?
TuringTux

@TuringTux w najnowszej wersji JavaFX, wyrzuci wyjątek, jeśli nie użyjesz Platform.runLater
bdshahab

-1

Chciałbym poprawić odpowiedź Evana Knowlesa: https://stackoverflow.com/a/30796829/2628125

W moim przypadku miałem klasę z handlerami dla części UI Component. Inicjalizacja:

this.dataText.textProperty().addListener((observable, oldValue, newValue) -> this.numericSanitization(observable, oldValue, newValue));

Oraz metoda numbericSanitization:

private synchronized void numericSanitization(ObservableValue<? extends String> observable, String oldValue, String newValue) {
    final String allowedPattern = "\\d*";

    if (!newValue.matches(allowedPattern)) {
        this.dataText.setText(oldValue);
    }
}

Zsynchronizowano słowo kluczoweDodano aby zapobiec możliwemu problemowi z blokadą renderowania w javafx, jeśli setText zostanie wywołany przed zakończeniem wykonywania starego. Jest to łatwe do odtworzenia, jeśli naprawdę szybko zaczniesz wpisywać złe znaki.

Kolejną zaletą jest to, że zachowujesz tylko jeden wzór do dopasowania i po prostu cofasz. Jest to lepsze, ponieważ można łatwo odrzucić rozwiązanie dla różnych wzorców sanityzacji.


-1
rate_text.textProperty().addListener(new ChangeListener<String>() {

    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        String s="";
        for(char c : newValue.toCharArray()){
            if(((int)c >= 48 && (int)c <= 57 || (int)c == 46)){
                s+=c;
            }
        }
        rate_text.setText(s);
    }
});

Działa to dobrze, ponieważ pozwala wprowadzić tylko wartość całkowitą i wartość dziesiętną (z kodem ASCII 46).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.