Reputation: 887
I'm using JavaFX and Scene Builder and I have a form with textfields. Three of these textfields are parsed from strings to doubles.
I want them to be school marks so they should only be allowed to be between 1.0 and 6.0. The user should not be allowed to write something like "2.34.4" but something like "5.5" or "2.9" would be ok.
Validation for the parsed fields:
public void validate(KeyEvent event) {
String content = event.getCharacter();
if ("123456.".contains(content)) {
// No numbers smaller than 1.0 or bigger than 6.0 - How?
} else {
event.consume();
}
}
How can I test if the user inputs a correct value?
I already searched on Stackoverflow and on Google but I didn't find a satisfying solution.
Upvotes: 12
Views: 71281
Reputation: 121
You can make a custom TextField that does input validation if you want.
import java.awt.Toolkit;
import javafx.event.EventHandler;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputControl;
import javafx.scene.input.KeyEvent;
/**
* A text field that limits the user to certain number of characters and
* prevents the user from typing certain characters
*
*
*/
public class CustomTextField extends TextField
{
/**
* The maximum number of characters this text field will allow
* */
private int maxNumOfCharacters;
/**
* A regular expression of characters that this text field does not allow
* */
private String unallowedCharactersRegEx;
/*
* If no max number of characters is specified the default value is set
* */
private static final int DEFAULT_MAX_NUM_OF_CHARACTERS = 1000;
public CustomTextField()
{
maxNumOfCharacters = DEFAULT_MAX_NUM_OF_CHARACTERS;
this.setOnKeyTyped(new EventHandler<KeyEvent>() {
public void handle(KeyEvent event)
{
// get the typed character
String characterString = event.getCharacter();
char c = characterString.charAt(0);
// if it is a control character or it is undefined, ignore it
if (Character.isISOControl(c) || characterString.contentEquals(KeyEvent.CHAR_UNDEFINED))
return;
// get the text field/area that triggered this key event and its text
TextInputControl source = (TextInputControl) event.getSource();
String text = source.getText();
// If the text exceeds its max length or if a character that matches
// notAllowedCharactersRegEx is typed
if (text.length() > maxNumOfCharacters
|| (unallowedCharactersRegEx != null && characterString.matches(unallowedCharactersRegEx)))
{
// remove the last character
source.deletePreviousChar();
// make a beep sound effect
Toolkit.getDefaultToolkit().beep();
}
}
});
}
public int getMaxNumOfCharacters()
{
return maxNumOfCharacters;
}
public void setMaxNumOfCharacters(int maxNumOfCharacters)
{
this.maxNumOfCharacters = maxNumOfCharacters;
}
public String getUnallowedCharactersRegEx()
{
return unallowedCharactersRegEx;
}
public void setUnallowedCharactersRegEx(String notAllowedRegEx)
{
this.unallowedCharactersRegEx = notAllowedRegEx;
}
}
Upvotes: 0
Reputation: 51
You can prevent illegal input using TextFormatter:
final Pattern pattern = Pattern.compile("(6\\.0)|([1-5]\\.[0-9])");
textField.setTextFormatter(new TextFormatter<>(new DoubleStringConverter(), 0.0, change -> {
final Matcher matcher = pattern.matcher(change.getControlNewText());
return (matcher.matches() || matcher.hitEnd()) ? change : null;
}));
Upvotes: 4
Reputation: 75
In case you can use a third party library:
Similar question has been aswered here: Form validator message .
For your case, you would choose a RegexValidator
to check the textfield input, and pass the regex that you arrived to from previous answers:
JFXTextField validationField = new JFXTextField();
validationField.setPromptText("decimal between 1.0 and 6.0");
RegexValidator validator = new RegexValidator();
validator.setRegexPattern("[1-5](\\.[0-9]{1,2}){0,1}|6(\\.0{1,2}){0,1}");
validator.setMessage("Please enter proper value");
validationField.getValidators().add(validator);
validationField.focusedProperty().addListener((observable, oldValue, newValue) -> {
if(!newValue)
validationField.validate();
});
Upvotes: 0
Reputation: 2164
textField.focusedProperty().addListener((arg0, oldValue, newValue) -> {
if (!newValue) { //when focus lost
if(!textField.getText().matches("[1-5]\\.[0-9]|6\\.0")){
//when it not matches the pattern (1.0 - 6.0)
//set the textField empty
textField.setText("");
}
}
});
you could also change the pattern to [1-5](\.[0-9]){0,1}|6(.0){0,1}
then 1,2,3,4,5,6
would also be ok (not only 1.0,2.0,...
)
update Here is a small test application with the values 1(.00) to 6(.00) allowed:
public class JavaFxSample extends Application {
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Enter number and hit the button");
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
Label label1To6 = new Label("1.0-6.0:");
grid.add(label1To6, 0, 1);
TextField textField1To6 = new TextField();
textField1To6.focusedProperty().addListener((arg0, oldValue, newValue) -> {
if (!newValue) { // when focus lost
if (!textField1To6.getText().matches("[1-5](\\.[0-9]{1,2}){0,1}|6(\\.0{1,2}){0,1}")) {
// when it not matches the pattern (1.0 - 6.0)
// set the textField empty
textField1To6.setText("");
}
}
});
grid.add(textField1To6, 1, 1);
grid.add(new Button("Hit me!"), 2, 1);
Scene scene = new Scene(grid, 300, 275);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Upvotes: 15
Reputation: 176
I would not advise you to use KeyEvent for that.
You should use a more classical way such as validated the user input when the user finish to fill the text field or click on a save button.
/**
* Called this when the user clicks on the save button or finish to fill the text field.
*/
private void handleSave() {
// If the inputs are valid we save the data
if(isInputValid()){
note=(DOUBLE.parseDouble(textField.getText()));
}else // do something such as notify the user and empty the field
}
/**
* Validates the user input in the text fields.
*
* @return true if the input is valid
*/
private boolean isInputValid() {
Boolean b= false;
if (!(textField.getText() == null || textFiled.getText().length() == 0)) {
try {
// Do all the validation you need here such as
Double d = Double.parseInt(textFiled.getText());
if ( 1.0<d<6.0){
b=true;
}
} catch (NumberFormatException e) {
}
return b;
}
Upvotes: 5