如何在 JavaFX 的 TextField 中强制双重输入? [英] How to force a double input in a TextField in JavaFX?

查看:28
本文介绍了如何在 JavaFX 的 TextField 中强制双重输入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何确保用户在给定的 TextField 中只输入双倍值?

我找到了一个 解决方案整数 但我无法将它用于双打.我应该写什么来代替 "\d*""[^\d]" 以使其适用于双打?

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?

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

推荐答案

如果用户输入无效值,则使用侦听器并恢复为有效值的方法可行,但如果您有其他侦听器,则可能会产生问题文本字段的 textProperty.那些侦听器将观察到无效值和有效值,因此他们必须知道过滤掉任何无效值.

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. Those listeners will observe the invalid values as well as the valid ones, so they have to know to filter out any invalid values.

更好的方法是使用 <代码>TextFormatter.TextFormatter 可以做两件事:

A better approach is to use a TextFormatter. The TextFormatter can do two things:

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

定义适当的过滤器可能很棘手:您希望允许用户进行任何合理的编辑.这意味着当用户正在编辑时,文本可能处于无效状态;例如您可能希望允许文本字段完全为空,即使这并不代表有效值.(否则,如果用户想要将1"更改为2",就会很烦人.)同样,您可能希望允许诸如-"和."之类的东西.

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; e.g. 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.

这是一个例子.如果需要,过滤器应该修改传递给它的更改,并且可以返回 null 以完全否决更改.此示例仅检查文本是否表示有效的编辑状态,如果是,则返回未修改的更改,否则否决它.格式化程序需要处理过滤器允许的任何文本并将其转换为双精度.这里任何不完整的东西都被表示为零.

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

如果需要,您可以使正则表达式更复杂,例如支持分组字符("1,000.0")、本地化("1.003,14159",如果这适用于语言环境)或科学记数法表示("1.003,14159">"6.022E23" 等),并强制执行最小值或最大值等.您甚至可以执行诸如修改更改之类的操作,以便用户在任何地方键入 -在文本中,它只是翻转数字的符号.(请参阅TextFormatter.更改文档以获得那种功能.)

You can make the regular expression more complex if needed, e.g. 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. (Refer to the TextFormatter.Change documentation for that kind of functionality.)

请注意,您可以直接从具有 ObjectProperty 的格式化程序获取和设置双精度值(由转换器提供).valueProperty().所以你可以做这样的事情

Note you can get and set the double value (as provided by the converter) directly from the formatter, which has an 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());
});

这是一个 SSCCE.第二个文本字段就在那里,以便您可以看到将焦点移动到不同控件的效果(它提交"该值并调用文本格式化程序上的侦听器,如果该值已更改;如果用户按回车键).

Here is a 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);
    }

}

这篇关于如何在 JavaFX 的 TextField 中强制双重输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆