I\'m trying to make a Sudoku game in JavaFX but I can\'t figure out how to only allow one letter to be entered. Would the answer to this to be to call the textfield and do:
You can use a TextFormatter to do this. The TextFormatter
can modify the changes that are made to the text in the text field if it has a filter associated with it. The filter is a function that takes a TextFormatter.Change
object and returns an object of the same type. It can return null
to veto the change entirely, or modify it.
So you can do
TextField textField = new TextField();
textField.setTextFormatter(new TextFormatter<String>((Change change) -> {
String newText = change.getControlNewText();
if (newText.length() > 1) {
return null ;
} else {
return change ;
}
});
Note though that the TextFormatter
can also be used to convert the text to a value of any type you like. In your case, it would make sense to convert the text to an Integer
, and also to only allow integer input. As a final addition to the user experience, you can modify the change so that if the user types a digit, it replaces the current content (instead of ignoring it if there are too many characters). The whole thing would look like this:
TextField textField = new TextField();
// converter that converts text to Integers, and vice-versa:
StringConverter<Integer> stringConverter = new StringConverter<Integer>() {
@Override
public String toString(Integer object) {
if (object == null || object.intValue() == 0) {
return "";
}
return object.toString() ;
}
@Override
public Integer fromString(String string) {
if (string == null || string.isEmpty()) {
return 0 ;
}
return Integer.parseInt(string);
}
};
// filter only allows digits, and ensures only one digit the text field:
UnaryOperator<Change> textFilter = c -> {
// if text is a single digit, replace current text with it:
if (c.getText().matches("[1-9]")) {
c.setRange(0, textField.getText().length());
return c ;
} else
// if not adding any text (delete or selection change), accept as is
if (c.getText().isEmpty()) {
return c ;
}
// otherwise veto change
return null ;
};
TextFormatter<Integer> formatter = new TextFormatter<Integer>(stringConverter, 0, textFilter);
formatter.valueProperty().addListener((obs, oldValue, newValue) -> {
// whatever you need to do here when the actual value changes:
int old = oldValue.intValue();
int updated = newValue.intValue();
System.out.println("Value changed from " + old + " to " + new);
});
textField.setTextFormatter(formatter);