JavaFX输入验证文本字段

12

我正在使用JavaFX和Scene Builder,我有一个带有文本字段的表单。其中三个文本字段从字符串解析为双精度浮点数。

我希望它们是学校成绩,因此只允许它们在1.0和6.0之间。用户不应该被允许写入像“2.34.4”这样的内容,但“5.5”或“2.9”之类的内容是可以的。

对解析字段进行验证:

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

如何测试用户输入的正确值?

我已经在Stackoverflow和Google上搜索过,但是没有找到一个令人满意的解决方案。

5个回答

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

    });

你也可以将模式更改为[1-5](\.[0-9]){0,1}|6(.0){0,1},这样1,2,3,4,5,6都可以通过验证(不仅限于1.0,2.0,...)。

更新:下面是一个小的测试应用程序,允许值在1(.00)到6(.00)之间:

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

}

非常感谢 @griFlo,但仍存在一个问题。我无法输入像“5.0”,“4.7”,“2.8”或“1.9”这样的值。您知道如何告诉程序只能有两位小数吗? - BRsmover
@BRsmover 你说的所有值都应该被允许(事实上,我刚刚用上面的代码测试了一下,它可以正常工作)。你所说的“两位小数”是什么意思?如果我理解正确,你可以使用这个正则表达式 [1-5](\.[0-9]{1,2}){0,1}|6(.0{1,2}){0,1} - griFlo
对不起,我可能误解了什么... 一切都运行得非常好!非常感谢! - BRsmover

5

我不建议你使用KeyEvent来实现这个功能。

你应该采用更传统的方式,比如在用户完成填写文本框或点击保存按钮时验证用户输入。

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

1
我想详细说明一下。我会调用验证方法3次:在保存操作上、在文本字段的动作事件上以及在失去焦点时。这样,用户在出现错误时可以立即得到响应,同时还可以防止保存错误数据。 - Jonathan Rosenne

4
您可以使用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;
}));

这个不起作用。它将文本锁定为“0.0”,并防止对其进行任何更改。即使光标也无法从文本末尾移动。 - Andreas detests censorship

0

如果您可以使用第三方库:

类似的问题已经在这里得到了解答:表单验证器消息

对于您的情况,您可以选择一个RegexValidator来检查文本字段输入,并传递您从之前的答案中得出的正则表达式:

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

0

如果需要,您可以创建一个自定义的TextField来进行输入验证。

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

}

不,这是不完整的,因为它无法通过粘贴来捕获无效输入,例如自从fx8u40以来,textFormatter是正确的选择。 - kleopatra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接