简体   繁体   English

如何在 JavaFX 的 TextField 中强制双重输入?

[英]How to force a double input in a TextField in JavaFX?

How to make sure an user inputs only double values in a given TextField?如何确保用户在给定的 TextField 中只输入双倍值

I found a solution for integers bu I can't manage to use it for doubles.我找到了整数解决方案,但我无法将其用于双打。 What should I write instead of the "\\\\d*" and "[^\\\\d]" to make it work for doubles?我应该写什么而不是"\\\\d*""[^\\\\d]"来使其适用于双打?

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

The approach of using a listener and reverting to valid values if invalid values are input by the user will work, but it can create issues if you have other listeners on the text field's textProperty .如果用户输入无效值,则使用侦听器并恢复为有效值的方法将起作用,但如果文本字段的textProperty上有其他侦听器,则可能会产生问题。 Those listeners will observe the invalid values as well as the valid ones, so they have to know to filter out any invalid values.这些侦听器将观察无效值以及有效值,因此他们必须知道过滤掉任何无效值。

A better approach is to use a TextFormatter .更好的方法是使用TextFormatter The TextFormatter can do two things: TextFormatter可以做两件事:

  1. Define a "Filter", which can veto, or modify, any changes made to the TextField 's text定义一个“过滤器”,它可以否决或修改对TextField文本所做的任何更改
  2. Define a "converter", which defines how to convert the text to and from values of any specific type (eg Double ) in your case.定义一个“转换器”,它定义了在您的情况下如何将文本与任何特定类型(例如Double )的值相互转换。

Defining the appropriate filter can be tricky: you want to allow any reasonable edits by the user.定义适当的过滤器可能很棘手:您希望允许用户进行任何合理的编辑。 This means the text may be in an invalid state while the user is editing;这意味着用户正在编辑时文本可能处于无效状态; eg you probably want to allow the text field to be completely empty, even though that does not represent a valid value.例如,您可能希望允许文本字段完全为空,即使这并不代表有效值。 (Otherwise, it becomes annoying to the user if, for example, they want to change "1" to "2".) Similarly you probably want to allow things like "-" and ".", etc. (否则,例如,如果他们想将“1”更改为“2”,就会让用户感到厌烦。)同样,您可能希望允许诸如“-”和“.”之类的东西。

Here is an example.这是一个例子。 The filter should modify the change that is passed to it, if needed, and can return null to completely veto a change.如果需要,过滤器应该修改传递给它的更改,并且可以返回null以完全否决更改。 This example simply checks if the text represents a valid editing state, and returns the change unmodified if it does, vetoing it otherwise.此示例仅检查文本是否表示有效的编辑状态,如果是,则返回未修改的更改,否则否决它。 The formatter needs to deal with any text that is allowed by the filter and convert it to a double.格式化程序需要处理过滤器允许的任何文本并将其转换为双精度。 Here anything that is incomplete is just represented as zero.这里任何不完整的东西都被表示为零。

Pattern validEditingState = Pattern.compile("-?(([1-9][0-9]*)|0)?(\\.[0-9]*)?");

UnaryOperator<TextFormatter.Change> filter = c -> {
    String text = c.getControlNewText();
    if (validEditingState.matcher(text).matches()) {
        return c ;
    } else {
        return null ;
    }
};

StringConverter<Double> converter = new StringConverter<Double>() {

    @Override
    public Double fromString(String s) {
        if (s.isEmpty() || "-".equals(s) || ".".equals(s) || "-.".equals(s)) {
            return 0.0 ;
        } else {
            return Double.valueOf(s);
        }
    }


    @Override
    public String toString(Double d) {
        return d.toString();
    }
};

TextFormatter<Double> textFormatter = new TextFormatter<>(converter, 0.0, filter);
TextField textField = new TextField();
textField.setTextFormatter(textFormatter);

You can make the regular expression more complex if needed, eg to support grouping characters ( "1,000.0" ), localization ( "1.003,14159" if that is appropriate for the locale), or scientific-notation-like representations ( "6.022E23" , etc), and to enforce minimum or maximum values, etc. You can even do things such as modifying the change, so that if the user types a - anywhere in the text, it just flips the sign of the number.如果需要,您可以使正则表达式更复杂,例如支持分组字符( "1,000.0" )、本地化( "1.003,14159"如果这适用于语言环境)或科学记数法表示( "6.022E23"等),并强制执行最小值或最大值等。您甚至可以执行诸如修改更改之类的操作,以便如果用户在文本中的任何位置键入 a - ,它只会翻转数字的符号。 (Refer to the TextFormatter.Change documentation for that kind of functionality.) (有关此类功能,请参阅TextFormatter.Change文档。)

Note you can get and set the double value (as provided by the converter) directly from the formatter, which has an ObjectProperty<Double> valueProperty() .请注意,您可以直接从具有ObjectProperty<Double> valueProperty()的格式化程序获取和设置双ObjectProperty<Double> valueProperty()值(由转换器提供ObjectProperty<Double> valueProperty() So you can do things like所以你可以做这样的事情

// update text field:
double value = ... ;
textFormatter.setValue(value);

// listen for changes in double value represented in text field
// Listener will be invoked when the user commits an edit:

textFormatter.valueProperty().addListener((ObservableValue<? extends Double> obs, Double oldValue, Double newValue) -> {
    System.out.println("User entered value: "+newValue.doubleValue());
});

Here is a SSCCE.这是一个 SSCCE。 The second text field is just there so that you can see the effect of moving focus to a different control (it "commits" the value and invokes the listener on the text formatter, if the value has changed; a similar thing happens if the user presses enter).第二个文本字段就在那里,以便您可以看到将焦点移动到不同控件的效果(如果值已更改,它会“提交”该值并调用文本格式化程序上的侦听器;如果用户按回车)。

import java.util.function.UnaryOperator;
import java.util.regex.Pattern;

import javafx.application.Application;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class NumericTextField extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Pattern validEditingState = Pattern.compile("-?(([1-9][0-9]*)|0)?(\\.[0-9]*)?");

        UnaryOperator<TextFormatter.Change> filter = c -> {
            String text = c.getControlNewText();
            if (validEditingState.matcher(text).matches()) {
                return c ;
            } else {
                return null ;
            }
        };

        StringConverter<Double> converter = new StringConverter<Double>() {

            @Override
            public Double fromString(String s) {
                if (s.isEmpty() || "-".equals(s) || ".".equals(s) || "-.".equals(s)) {
                    return 0.0 ;
                } else {
                    return Double.valueOf(s);
                }
            }


            @Override
            public String toString(Double d) {
                return d.toString();
            }
        };

        TextFormatter<Double> textFormatter = new TextFormatter<>(converter, 0.0, filter);
        TextField textField = new TextField();
        textField.setTextFormatter(textFormatter);

        textFormatter.valueProperty().addListener((ObservableValue<? extends Double> obs, Double oldValue, Double newValue) -> {
            System.out.println("User entered value: "+newValue.doubleValue());
        });

        VBox root = new VBox(5, textField, new TextField());
        root.setAlignment(Pos.CENTER);
        primaryStage.setScene(new Scene(root, 250, 250));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

You can use the java regex on doubles and replace non-number characters with numbers.您可以在双打上使用 java 正则表达式并用数字替换非数字字符。 In you have to specify the number of digits allowed in the integer part, for example 1,10.您必须指定整数部分中允许的位数,例如 1,10。

textField.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        if (!newValue.matches("[0-9]{<range>}(\\.[0-9]*)?")) {
            textField.setText(newValue.replaceAll("[^\\d.]", ""));
            StringBuilder aus = new StringBuilder(newValue);
            boolean firstPointFound = false;
            for (int i = 0; i < aus.length(); i++){
                if(aus.charAt(i) == '.') {
                    if(!firstPointFound)
                        firstPointFound = true;
                    else
                        aus.deleteCharAt(i);
                }
            }
            newValue = aus.toString();
        }
    }
});

You could make use of Double.parseDoubleDouble Javadoc .您可以使用 Double.parseDoubleDouble Javadoc This will do the parsing for you, rather than writing your own double validation.这将为您进行解析,而不是编写您自己的双重验证。 You can then check for a number format exception or null pointer exception.然后,您可以检查数字格式异常或空指针异常。

    try
    {
        Double.parseDouble(newValue);
        // Valid double
    }
    catch (NullPointerException | NumberFormatException ex)
    {
        // Not valid double
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM