Wie implementieren Sie ein Nummernfeld in Javafx 2.0?
-
28-10-2019 - |
Frage
Ich muss ein Zahlenfeld in meine Benutzeroberfläche einfügen. Daher muss ich die Schlüsselereignisse in einem Textfeld überprüfen, um zu überprüfen, ob das Eingabezeichen eine Zahl ist. Ich habe eine Klasse erstellt, indem ich Textfield erweitert. Wenn in der Textfeldklasse eine Methode vorhanden ist, die KeyEvents verarbeitet, kann ich diese Methode einfach mit Anzügen zu Zahlenfeld übergeben. Irgendwelche Ideen?
Vielen Dank
Lösung 4
Fand eine Lösung. :)
public class NumFieldFX extends TextField {
public NumFieldFX() {
this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
public void handle( KeyEvent t ) {
char ar[] = t.getCharacter().toCharArray();
char ch = ar[t.getCharacter().toCharArray().length - 1];
if (!(ch >= '0' && ch <= '9')) {
System.out.println("The char you entered is not a number");
t.consume();
}
}
});
}
}
Andere Tipps
Update 27. Mai 2016
Java 8u40 stellte die vor TextFormatter Klasse, die die empfohlene Methode zur Durchführung dieser Funktionalität ist (obwohl die in dieser Antwort bereitgestellte Lösung weiterhin funktioniert). Weitere Informationen finden Sie unter UWEs Antwort, Hassans Antwort und andere Antworten, in denen TextFormatier der folgenden Frage erwähnt wird:
Es gibt auch diese Lösung aus einer anderen Antwort auf diese Frage, die ich nicht ausprobiert habe, aber gut aussieht und ein Stackoverflow -Moderator gelöscht habe:
TextField numberField = new TextField();
numberField.setTextFormatter(new TextFormatter<>(new NumberStringConverter()));
Der obige Code verfehlt den Unaryoperator -Filter für die Textformatter, die Sie normalerweise auch benötigen ). Um die Lösung für die Verwendung eines Filters zu erweitern, kann der folgende Code wie diesen verwendet werden:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.stage.Stage;
import javafx.util.converter.NumberStringConverter;
import java.text.ParsePosition;
import java.util.function.UnaryOperator;
public class NumberConverterFieldTest extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
TextField numberField = new TextField();
NumberStringFilteredConverter converter = new NumberStringFilteredConverter();
final TextFormatter<Number> formatter = new TextFormatter<>(
converter,
0,
converter.getFilter()
);
numberField.setTextFormatter(formatter);
formatter.valueProperty().addListener((observable, oldValue, newValue) ->
System.out.println(newValue)
);
stage.setScene(new Scene(numberField));
stage.show();
}
class NumberStringFilteredConverter extends NumberStringConverter {
// Note, if needed you can add in appropriate constructors
// here to set locale, pattern matching or an explicit
// type of NumberFormat.
//
// For more information on format control, see
// the NumberStringConverter constructors
// DecimalFormat class
// NumberFormat static methods for examples.
// This solution can instead extend other NumberStringConverters if needed
// e.g. CurrencyStringConverter or PercentageStringConverter.
public UnaryOperator<TextFormatter.Change> getFilter() {
return change -> {
String newText = change.getControlNewText();
if (newText.isEmpty()) {
return change;
}
ParsePosition parsePosition = new ParsePosition( 0 );
Object object = getNumberFormat().parse( newText, parsePosition );
if ( object == null || parsePosition.getIndex() < newText.length()) {
return null;
} else {
return change;
}
};
}
}
}
Bearbeiten Sie beim Ausführen des obigen Beispiels das Eingabebuch und drücken System.out
wenn geändert).
Für ein Tutorial siehe:
- JavaRld TextFormatter Artikel (Achten Sie auf nervige Popup-Anzeigen).
Dies ist dieselbe Lösung, die sich verweist. Ich habe sie jedoch gerade in ein vollständig ausführbares Programm platziert, um ein Beispiel im Kontext anzugeben, und den regulären Ausdruck geändert (durch Hinzufügen *
am Ende), damit das Kopieren und Einfügen funktioniert und nicht das Problem hat, auf das Uluk bezieht. Die Lösung scheint ziemlich einfach und wird wahrscheinlich für die meisten Zwecke ausreichen:
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class NumericTextFieldTest extends Application {
public static void main(String[] args) { launch(args); }
@Override public void start(Stage stage) {
TextField numberField = new TextField() {
@Override public void replaceText(int start, int end, String text) {
if (text.matches("[0-9]*")) {
super.replaceText(start, end, text);
}
}
@Override public void replaceSelection(String text) {
if (text.matches("[0-9]*")) {
super.replaceSelection(text);
}
}
};
stage.setScene(new Scene(numberField));
stage.show();
}
}
Alternative Lösungen
Möglicherweise interessieren Sie sich auch für meine alternative Lösung in Javafx Beispiel für die Bindung eines Schiebereglerwerts an ein bearbeitbares Textfeld. In dieser Lösung erweitere ich das Textfeld, um eine IntegerProperty auf dem Feld für einfache Bindungszwecke aufzudecken. Die alternative Lösung ähnelt dem, das durch das ursprüngliche Poster in ihrer aktualisierten Frage beschrieben wurde (dh ein Ereignisfilter wird hinzugefügt, um Eingabedaten aus Schlüsselereignissen einzuschränken), aber zusätzlich wird ein ChangeListener auf der Texteigenschaft des Textfield hinzugefügt, um sicherzustellen werden nur akzeptiert, wenn sie numerisch sind.
Es gibt einige andere Lösungen für diese Frage im Javafx Forum -Thread Numerisches Textfeld in Javafx 2.0? welches einen Verweis auf die enthält Zahlenfelder von FXExperience -Steuerelementen.
Es gibt ein Tipp an Fxexperience Das befasst sich einfach mit einem solchen Problem. Um zu paraphrasieren, erweitern Sie die TextField
und überschreiben die replaceText()
und replaceSelection()
Methoden, filtern alle Eingaben, die keine Zahl sind.
Nach der Implementierung sollten beide Methoden dieser Vorlage folgen:
if (!newText.matches("[0-9]")) {
super.call(allParams)
}
Hier ist das benutzerdefinierte Feld, das ich geschrieben habe. Es behandelt beide Zahlen nur Eingabe und auch maximal. Es ist eine benutzerdefinierte Steuerung, die in FXML verwendet werden kann, und auch die Eigenschaften können in FXML selbst eingestellt werden.
package fxml;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.IntegerPropertyBase;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.TextField;
public class CustomTextField extends TextField {
/**
* numericOnly property if set, will allow accept only numeric input.
*/
private BooleanProperty numericOnly = new SimpleBooleanProperty(this,
"numericOnly", false);
public final boolean isNumericOnly() {
return numericOnly.getValue();
}
public final void setNumericOnly(boolean value) {
numericOnly.setValue(value);
}
public final BooleanProperty numericOnlyProperty() {
return numericOnly;
}
/**
* maxSize property , determines the maximum size of the text that can be
* input.
*/
public IntegerProperty maxSize = new IntegerPropertyBase(1000) {
@Override
public String getName() {
return "maxSize";
}
@Override
public Object getBean() {
return CustomTextField.this;
}
};
public final IntegerProperty maxSizeProperty() {
return maxSize;
};
public final int getMaxSize() {
return maxSize.getValue();
}
public final void setMaxSize(int value) {
maxSize.setValue(value);
}
/**
* this method is called when user inputs text into the textField
*/
@Override
public void replaceText(int start, int end, String text) {
if (numericOnly.getValue() && !text.equals("")) {
if (!text.matches("[0-9]")) {
return;
}
}
if (getText().length() < getMaxSize() || text.equals("")) {
super.replaceText(start, end, text);
}
}
/**
* this method is called when user pastes text into the textField
*/
@Override
public void replaceSelection(String text) {
if (numericOnly.getValue() && !text.equals("")) {
if (!text.matches("[0-9]+")) {
return;
}
}
super.replaceSelection(text);
if (getText().length() > getMaxSize()) {
String maxSubString = getText().substring(0, getMaxSize());
setText(maxSubString);
positionCaret(getMaxSize());
}
}
}
Für eine Reihe von Textfilmen (Dezimalpunkt enthalten)
Arrays.asList(txtLongitude, txtLatitude, txtAltitude, txtSpeed, txtOrientation).forEach(textField ->
textField.textProperty().addListener((observable, oldValue, newValue) ->
textField.setText(newValue.matches("^[0-9]*\\.?[0-9]*$") ? newValue : oldValue)
));
Kombinierte Baijifeilong- und Ajay Prakash -Lösung zur Unterstützung von Dezimaleingaben
package com.mazeworks.cloudhms.view.components;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.IntegerPropertyBase;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.TextField;
public class NumericTextField extends TextField {
/**
* numericOnly property if set, will allow accept only numeric input.
*/
private BooleanProperty numericOnly = new SimpleBooleanProperty(this,
"numericOnly", false);
public final boolean isNumericOnly() {
return numericOnly.getValue();
}
public final void setNumericOnly(boolean value) {
numericOnly.setValue(value);
}
public final BooleanProperty numericOnlyProperty() {
return numericOnly;
}
/**
* maxSize property, determines the maximum size of the text that
can be
* input.
*/
public IntegerProperty maxSize = new IntegerPropertyBase(1000) {
@Override
public String getName() {
return "maxSize";
}
@Override
public Object getBean() {
return NumericTextField.this;
}
};
public final IntegerProperty maxSizeProperty() {
return maxSize;
}
;
public final int getMaxSize() {
return maxSize.getValue();
}
public final void setMaxSize(int value) {
maxSize.setValue(value);
}
/**
* this method is called when user inputs text into the textField
*/
@Override
public void replaceText(int start, int end, String text) {
if (numericOnly.getValue() && !text.equals("")) {
if (!text.matches("^[0-9]*\\.?[0-9]*$")) {
return;
}
}
if (getText().length() < getMaxSize() || text.equals("")) {
super.replaceText(start, end, text);
}
}
/**
* this method is called when user pastes text into the textField
*/
@Override
public void replaceSelection(String text) {
if (numericOnly.getValue() && !text.equals("")) {
if (!text.matches("^[0-9]*\\.?[0-9]*$")) {
return;
}
}
super.replaceSelection(text);
if (getText().length() > getMaxSize()) {
String maxSubString = getText().substring(0, getMaxSize());
setText(maxSubString);
positionCaret(getMaxSize());
}
}
}
Geerbt von Textfeld und überschreiben Austausch Um einen Doppelwerte nur für Textfeld zu erhalten:
@Override
public void replaceText(int start, int end, String text) {
String preText = getText(0, start);
String afterText = getText(end, getLength());
String toBeEnteredText = preText + text + afterText;
// Treat the case where the user inputs proper text and is not inputting backspaces or other control characters
// which would be represented by an empty text argument:
if (!text.isEmpty() && text.matches("\\d|\\.")) {
Logger.getAnonymousLogger().info("Paring non-empty.");
try {
Logger.getAnonymousLogger().info("Parsing " + toBeEnteredText);
Double.parseDouble(toBeEnteredText);
super.replaceText(start, end, text);
} catch (Exception ignored) {
}
}
// If the user used backspace or del, the result text is impossible to not parse as a Double/Integer so just
// enter that text right ahead:
if (text.isEmpty()) {
super.replaceText(start, end, text);
}
}