Was ist die empfohlene Methode, um ein numerisches TextField in JavaFX zu erstellen?

84

Ich muss die Eingabe in ein TextField auf ganze Zahlen beschränken. Irgendein Rat?

Harry Mitchell
quelle
3
Hinweis: Das Anhören der textProperty ist falsch ! Das war das Beste, was man machen konnte, bevor man einen TextFormatter hatte (seit fx8u40 oder so). Seitdem gilt die Grundregel: Im Allgemeinen wird es als schlechte Praxis angesehen, den beobachteten Wert in dieser Methode zu ändern, und die Verwendung eines TextFormatter ist die einzig akzeptable Lösung.
Kleopatra

Antworten:

115

Sehr alter Thread, aber dieser scheint ordentlicher zu sein und entfernt nicht numerische Zeichen, wenn er eingefügt wird.

// 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]", ""));
        }
    }
});
Evan Knowles
quelle
3
Funktioniert wunderbar. Beachten Sie, dass Sie stattdessen auch \\D+(oder nur \\D) anstelle von verwenden können [^\\d], wenn Sie einige Zeichen speichern möchten.
Ricky3350
5
Noch einfacher ist es, den Text auf oldValue zurückzusetzen. Auf diese Weise müssen Sie nicht mit Regex-Ersetzungen herumspielen (was bei mir leider überhaupt nicht funktioniert hat).
geisterfurz007
@ geisterfurz007 Dies gibt jedoch die Möglichkeit, nicht numerische Zeichen aus eingefügtem Text zu entfernen.
Evan Knowles
10
Veraltet, siehe TextFormatter-Antwort unten.
Gerardw
3
Könnte auch möglicherweise nur verwenden Integer.parseInt(newValue)und verwenden tryund catcheinen Fehler aufNumberFormatException
Pixel
43

Update Apr 2016

Diese Antwort wurde vor einigen Jahren erstellt und die ursprüngliche Antwort ist jetzt weitgehend veraltet.

Seit Java 8u40 verfügt Java über einen TextFormatter, der normalerweise am besten geeignet ist, um die Eingabe bestimmter Formate wie z. B. Zahlen in JavaFX TextFields zu erzwingen:

Siehe auch andere Antworten auf diese Frage, in denen TextFormatter ausdrücklich erwähnt wird.


Ursprüngliche Antwort

Es gibt einige Beispiele dafür in diesem Kern , ich habe eines der folgenden Beispiele dupliziert:

// 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()));
      }
    });
  }
}
Juwelensee
quelle
41

Ich weiß, dass dies ein ziemlich alter Thread ist, aber für zukünftige Leser ist hier eine andere Lösung, die ich ziemlich intuitiv fand:

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]*");
    }
}

Edit: Danke none_ und SCBoy für deine Verbesserungsvorschläge.

Burkhard
quelle
1
Weiß jemand, welcher Regex für Dezimalzahlen verwendet werden soll (z. B. 123.456)? Der Wert des Validierungsfunktionsparameters "Text" (Text) ist das zuletzt vom Benutzer bearbeitete Zeichen, nicht die gesamte Zeichenfolge im Textfeld. Daher stimmt der reguläre Ausdruck möglicherweise nicht richtig überein. Zum Beispiel benutze ich diesen Befehl wie text.matches("\\d+");
mils
1
@mils Schau hier und hier .
Vellotis
Ich denke, dass dies eine gute Lösung ist, aber ich würde eines ändern. Anstatt text.matches ("[0-9] *") zu schreiben, würde ich eine Variable für das Muster erstellen und es kompilieren. In Ihrem Code wird das Muster jedes Mal kompiliert, wenn jemand ein Zeichen in ein Feld schreibt, was für CPU und Speicher kostspielig ist. Also würde ich eine Variable hinzufügen: private static Pattern integerPattern = Pattern.compile ("[0-9] *"); Und ersetzen Sie validate body durch: integerPattern.matcher (text) .matches ();
P. Jowko
37

Ab JavaFX 8u40 können Sie ein TextFormatter-Objekt für ein Textfeld festlegen:

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

Dadurch werden sowohl Unterklassen- als auch doppelte Änderungsereignisse vermieden, die Sie erhalten, wenn Sie der Texteigenschaft einen Änderungslistener hinzufügen und den Text in diesem Listener ändern.

Uwe
quelle
30

Das TextInputhat ein TextFormatter, mit dem die eingegebenen Textarten formatiert, konvertiert und begrenzt werden können.

Das TextFormatterhat einen Filter, mit dem Eingaben verworfen werden können. Wir müssen dies festlegen, um alles abzulehnen, was keine gültige Ganzzahl ist. Es gibt auch einen Konverter, den wir einstellen müssen, um den Zeichenfolgenwert in einen ganzzahligen Wert zu konvertieren, den wir später binden können.

Erstellen wir einen wiederverwendbaren Filter:

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

Der Filter kann eines von drei Dingen ausführen: Er kann die Änderung unverändert zurückgeben, um sie so zu akzeptieren, wie sie ist, er kann die Änderung auf eine Weise ändern, die er für geeignet hält, oder er kann zurückkehren null, um die Änderung insgesamt abzulehnen.

Wir werden den Standard IntegerStringConverterals Konverter verwenden.

Alles zusammen haben wir:

TextField textField = ...;

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

textField.setTextFormatter(formatter);

Wenn Sie keinen wiederverwendbaren Filter benötigen, können Sie stattdessen diesen ausgefallenen Einzeiler verwenden:

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

Ich mag keine Ausnahmen, deshalb habe ich die matchesFunktion von String-Class verwendet

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);
        }
    }
});
thatsIch
quelle
1
manchmal hast du eine ausnahme, weil der nuber zu groß sein könnte.
schlagi123
1
Tipp: Ersetzen Sie den regulären Ausdruck "\\ d +" durch "\\ d *". Auf diese Weise können Sie alle Zeichen aus dem Texteingabefeld entfernen (verwenden Sie die Rücktaste / Löschen, um das Feld zu löschen).
Guus
1
Vergessen Sie nicht, die Caret-Position einzustellen, nachdem Sie sie auf den alten Wert zurückgesetzt haben:textField.positionCaret(textField.getLength());
Hsson
Ändern Sie die Faust-if-Bedingung in: if (newValue.matches("\\d*") && newValue.getText().length < 5) Wenn Sie die Eingabe in diesem Fall auf 4 Stellen beschränken möchten.
Cappuccino90
@ Cappuccino90 Sie sollten die Anweisungen wechseln, da die Längenprüfung bei jedem Treffer viel billiger ist als das Parsen eines
regulären Ausdrucks
9

Ab Java SE 8u40 können Sie für diesen Bedarf eine " Ganzzahl " verwenden Spinner, mit der Sie eine gültige Ganzzahl sicher auswählen können, indem Sie die Aufwärtspfeil- / Abwärtspfeiltasten der Tastatur oder die mit den Aufwärtspfeil- / Abwärtspfeil-Tasten verwenden.

Sie können auch einen Min- , einen Max- und einen Anfangswert definieren, um die zulässigen Werte und einen Betrag zu begrenzen, um den pro Schritt erhöht oder verringert werden soll.

Beispielsweise

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

Beispiel eines Ergebnisses mit einem " Integer " -Spinner und einem " Double " -Spinner

Geben Sie hier die Bildbeschreibung ein

Ein Drehfeld ist ein einzeiliges Textfeldsteuerelement, mit dem der Benutzer eine Zahl oder einen Objektwert aus einer geordneten Folge solcher Werte auswählen kann. Spinner bieten normalerweise ein Paar winziger Pfeiltasten zum Durchlaufen der Elemente der Sequenz. Die Aufwärtspfeil- / Abwärtspfeiltasten der Tastatur durchlaufen ebenfalls die Elemente. Dem Benutzer kann auch gestattet werden, einen (legalen) Wert direkt in den Spinner einzugeben. Obwohl Kombinationsfelder ähnliche Funktionen bieten, werden Spinner manchmal bevorzugt, weil sie keine Dropdown-Liste benötigen, die wichtige Daten verdecken kann, und weil sie Funktionen wie das Umbrechen vom Maximalwert zurück zum Minimalwert ermöglichen (z. von der größten positiven ganzen Zahl bis 0).

Weitere Details zur Spinner-Steuerung

Nicolas Filotto
quelle
Menschen sollten nicht der Spinner nicht bei Texteingabe validieren oder Fokus verlieren
geometrisch
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);
        }
    }
});

Die ifKlausel ist wichtig, um Eingaben wie 0.5d oder 0.7f zu verarbeiten, die von Int.parseInt () korrekt analysiert werden, aber nicht im Textfeld erscheinen sollten.

Ubuntudroid
quelle
9
Woot? Seit wann wird 0.5d von Integer.parseInt () korrekt analysiert?! Es löst eine java.lang.NumberFormatException aus: Für Eingabezeichenfolge: "0.5d" (wie erwartet, da es sich nicht um eine Ganzzahl handelt)
Burkhard
6

Die bevorzugte Antwort kann noch kleiner sein, wenn Sie Java 1.8 Lambdas verwenden

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

Versuchen Sie diesen einfachen Code, der die Arbeit erledigt.

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;
    }
}));
Hassan Latif
quelle
3

Wenn Sie denselben Listener auf mehr als ein TextField anwenden möchten, ist dies die einfachste Lösung:

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);
Javasuns
quelle
3

Dieser hat für mich gearbeitet.

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);
            }
        }
    });
}
Martin
quelle
3

Ich möchte mit meiner Idee helfen, Evan Knowles Antwort mit TextFormatterJavaFX 8 zu kombinieren

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

also viel glück;) bleib ruhig und codiere java

Salah Eddine Chaibi
quelle
2

Hier ist eine einfache Klasse, die einige grundlegende Validierungen TextFieldmit verarbeitetTextFormatter JavaFX 8u40 behandelt

BEARBEITEN:

(Code zu Floerns Kommentar hinzugefügt)

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

}

Sie können es so verwenden:

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

oder Sie können es in einer fxml-Datei instanziieren und auf ein customTextField mit den entsprechenden Eigenschaften anwenden.

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

Code auf Github

jns
quelle
2

Das benutze ich:

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

    }
});

Das gleiche in der Lambda-Notation wäre:

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

Mit dieser Methode kann TextField die gesamte Verarbeitung abschließen (Kopieren / Einfügen / Rückgängig machen). Es ist nicht erforderlich, Klassen zu erweitern, und Sie können nach jeder Änderung entscheiden, was mit neuem Text geschehen soll (um ihn auf Logik zu verschieben, zum vorherigen Wert zurückzukehren oder ihn sogar zu ändern).

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

Fügen Sie für Ihren Fall einfach diese Logik hinzu. Funktioniert perfekt.

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

Mmmm. Ich bin vor Wochen auf dieses Problem gestoßen. Da die API keine Steuerung bietet, um dies zu erreichen,
möchten Sie möglicherweise eine eigene verwenden.
Ich habe so etwas benutzt wie:

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

Es wird genauso verwendet wie ein normales TextBox, hat
aber auch ein valueAttribut, das die eingegebene Ganzzahl speichert.
Wenn das Steuerelement den Fokus verliert, es bestätigt den Wert und kehrt es (wenn nicht gültig ist).

Alba Mendez
quelle
2
Welche Sprache ist das?
Stealth Rabbi
Es ist JavaFX Script Rabbi, es ist veraltet .
Jewelsea
0

Dieser Code Lassen Sie Ihr Textfeld nur eine Nummer akzeptieren

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));
            }
        }
    });
Amine Harbaoui
quelle
0

Dieser Code funktioniert auch dann gut, wenn Sie versuchen, ihn zu kopieren / einzufügen.

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

    }
});
Ahmed Jaouadi
quelle
-1

In den letzten Aktualisierungen von JavaFX müssen Sie neuen Text in der Platform.runLater-Methode wie folgt festlegen:

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

Es ist eine gute Idee, auch die Caret-Position festzulegen.

bdshahab
quelle
1
Vielen Dank für Ihre Antwort! Können Sie ein wenig erklären, warum dies Platform.runLatererforderlich ist?
TuringTux
@TuringTux in der neuesten Version von JavaFX, es wird eine Ausnahme
auslösen,
-1

Ich möchte Evan Knowles Antwort verbessern: https://stackoverflow.com/a/30796829/2628125

In meinem Fall hatte ich eine Klasse mit Handlern für den UI-Komponententeil. Initialisierung:

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

Und die numbericSanitization-Methode:

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

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

Schlüsselwort synchronisiert wird hinzugefügt, um mögliche Probleme mit der Render-Sperre in javafx zu vermeiden, wenn setText aufgerufen wird, bevor die Ausführung des alten abgeschlossen ist. Es ist einfach zu reproduzieren, wenn Sie sehr schnell falsche Zeichen eingeben.

Ein weiterer Vorteil ist, dass Sie nur ein Muster beibehalten und nur einen Rollback durchführen. Es ist besser, weil Sie die Lösung für verschiedene Desinfektionsmuster leicht abstragieren können.

Oleksandr Knyga
quelle
-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);
    }
});

Dies funktioniert einwandfrei, da Sie nur einen ganzzahligen Wert und einen Dezimalwert eingeben können (mit ASCII-Code 46).

ShubhamWanne
quelle