在JavaFX中创建数字TextField的推荐方法是什么?

Har*_*ell 77 javafx input filter textfield

我需要将输入限制为TextField为整数.有什么建议?

Eva*_*les 101

非常旧的线程,但这似乎更整洁,如果粘贴,剥去非数字字符.

// force the field to be numeric only
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]", ""));
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 过时,请参阅下面的TextFormatter答案. (5认同)
  • 工作奇妙.请注意,如果要保存几个字符,也可以使用`\\ D +`(或只是`\\ D`)而不是`[^ \\ d]`. (3认同)
  • 更简单的是将文本设置回oldValue.这样你就不必乱用正则表达式替换(不幸的是,它根本不适用于我). (3认同)
  • 也可能只使用Integer.parseInt(newValue)并使用try和catch来发现NumberFormatException上的错误。 (3认同)

Bur*_*ard 39

我知道这是一个相当古老的线程,但对于未来的读者来说,这是另一个我发现非常直观的解决方案:

public class NumberTextField extends TextField
{

    @Override
    public void replaceText(int start, int end, String text)
    {
        if (validate(text))
        {
            super.replaceText(start, end, text);
        }
    }

    @Override
    public void replaceSelection(String text)
    {
        if (validate(text))
        {
            super.replaceSelection(text);
        }
    }

    private boolean validate(String text)
    {
        return text.matches("[0-9]*");
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:感谢none_SCBoy,以表示您的建议改进.


jew*_*sea 37

2016年4月更新

这个答案是几年前创建的,原来的答案现在基本上已经过时了.

从Java 8u40开始,Java有一个TextFormatter,它通常最适合强制输入特定格式,例如JavaFX TextFields上的数字:

另请参阅此问题的其他答案,其中特别提到TextFormatter.


原始答案

在这个要点中有一些这样的例子,我复制了下面的一个例子:

// helper text field subclass which restricts text input to a given range of natural int numbers
// and exposes the current numeric int value of the edit box as a value property.
class IntField extends TextField {
  final private IntegerProperty value;
  final private int minValue;
  final private int maxValue;

  // expose an integer value property for the text field.
  public int  getValue()                 { return value.getValue(); }
  public void setValue(int newValue)     { value.setValue(newValue); }
  public IntegerProperty valueProperty() { return value; }

  IntField(int minValue, int maxValue, int initialValue) {
    if (minValue > maxValue) 
      throw new IllegalArgumentException(
        "IntField min value " + minValue + " greater than max value " + maxValue
      );
    if (maxValue < minValue) 
      throw new IllegalArgumentException(
        "IntField max value " + minValue + " less than min value " + maxValue
      );
    if (!((minValue <= initialValue) && (initialValue <= maxValue))) 
      throw new IllegalArgumentException(
        "IntField initialValue " + initialValue + " not between " + minValue + " and " + maxValue
      );

    // initialize the field values.
    this.minValue = minValue;
    this.maxValue = maxValue;
    value = new SimpleIntegerProperty(initialValue);
    setText(initialValue + "");

    final IntField intField = this;

    // make sure the value property is clamped to the required range
    // and update the field's text to be in sync with the value.
    value.addListener(new ChangeListener<Number>() {
      @Override public void changed(ObservableValue<? extends Number> observableValue, Number oldValue, Number newValue) {
        if (newValue == null) {
          intField.setText("");
        } else {
          if (newValue.intValue() < intField.minValue) {
            value.setValue(intField.minValue);
            return;
          }

          if (newValue.intValue() > intField.maxValue) {
            value.setValue(intField.maxValue);
            return;
          }

          if (newValue.intValue() == 0 && (textProperty().get() == null || "".equals(textProperty().get()))) {
            // no action required, text property is already blank, we don't need to set it to 0.
          } else {
            intField.setText(newValue.toString());
          }
        }
      }
    });

    // restrict key input to numerals.
    this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
      @Override public void handle(KeyEvent keyEvent) {
        if (!"0123456789".contains(keyEvent.getCharacter())) {
          keyEvent.consume();
        }
      }
    });

    // ensure any entered values lie inside the required range.
    this.textProperty().addListener(new ChangeListener<String>() {
      @Override public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
        if (newValue == null || "".equals(newValue)) {
          value.setValue(0);
          return;
        }

        final int intValue = Integer.parseInt(newValue);

        if (intField.minValue > intValue || intValue > intField.maxValue) {
          textProperty().setValue(oldValue);
        }

        value.set(Integer.parseInt(textProperty().get()));
      }
    });
  }
}
Run Code Online (Sandbox Code Playgroud)


Uwe*_*Uwe 32

从JavaFX 8u40开始,您可以在文本字段上设置TextFormatter对象:

UnaryOperator<Change> filter = change -> {
    String text = change.getText();

    if (text.matches("[0-9]*")) {
        return change;
    }

    return null;
};
TextFormatter<String> textFormatter = new TextFormatter<>(filter);
fieldNport = new TextField();
fieldNport.setTextFormatter(textFormatter);
Run Code Online (Sandbox Code Playgroud)

这样可以避免在将更改侦听器添加到text属性并修改该侦听器中的文本时获得的子类化和重复更改事件.


Emi*_* L. 28

TextInputTextFormatter可用于格式化,转换和限制类型的文本,可以是输入的.

TextFormatter具有可用于拒绝输入的滤波器.我们需要设置它来拒绝任何不是有效整数的东西.它还有一个转换器,我们需要将其设置为将字符串值转换为我们稍后可以绑定的整数值.

让我们创建一个可重用的过滤器:

public class IntegerFilter implements UnaryOperator<TextFormatter.Change> {
    private final static Pattern DIGIT_PATTERN = Pattern.compile("\\d*");

    @Override
    public Change apply(TextFormatter.Change aT) {
        return DIGIT_PATTERN.matcher(aT.getText()).matches() ? aT : null;
    }
}
Run Code Online (Sandbox Code Playgroud)

过滤器可以执行以下三种操作之一:它可以返回未修改的更改以按原样接受它,它可以以它认为合适的某种方式更改更改,或者它可以返回null以拒绝所有更改.

我们将使用该标准IntegerStringConverter作为转换器.

总而言之,我们有:

TextField textField = ...;

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), // Standard converter form JavaFX
    defaultValue, 
    new IntegerFilter());
formatter.valueProperty().bindBidirectional(myIntegerProperty);

textField.setTextFormatter(formatter);
Run Code Online (Sandbox Code Playgroud)

如果你不需要一个可重复使用的过滤器,你可以做这个花哨的单行:

TextFormatter<Integer> formatter = new TextFormatter<>(
    new IntegerStringConverter(), 
    defaultValue,  
    c -> Pattern.matches("\\d*", c.getText()) ? c : null );
Run Code Online (Sandbox Code Playgroud)


tha*_*Ich 21

我不喜欢异常,因此我使用了matchesString-Class中的函数

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable, String oldValue, 
        String newValue) {
        if (newValue.matches("\\d*")) {
            int value = Integer.parseInt(newValue);
        } else {
            text.setText(oldValue);
        }
    }
});
Run Code Online (Sandbox Code Playgroud)


小智 8

我想通过将 Evan Knowles 的答案与TextFormatterJavaFX 8 的答案相结合来帮助实现我的想法

textField.setTextFormatter(new TextFormatter<>(c -> {
    if (!c.getControlNewText().matches("\\d*")) 
        return null;
    else
        return c;
    }
));
Run Code Online (Sandbox Code Playgroud)

祝你好运;)保持冷静并编写 java 代码


ves*_*ion 7

如果您使用Java 1.8 Lambda,则首选答案可能更小。

textfield.textProperty().addListener((observable, oldValue, newValue) -> {
    if (newValue.matches("\\d*")) return;
    textfield.setText(newValue.replaceAll("[^\\d]", ""));
});
Run Code Online (Sandbox Code Playgroud)


Nic*_*tto 7

Java SE 8u40开始,出于这种需要,您可以使用" 整数 " Spinner,通过使用键盘的向上箭头/向下箭头键或向上箭头/向下箭头提供的按钮安全地选择有效整数.

您还可以定义最小值,最大值初始值,以限制每步的允许值和增加或减少的量.

例如

// Creates an integer spinner with 1 as min, 10 as max and 2 as initial value
Spinner<Integer> spinner1 = new Spinner<>(1, 10, 2);
// Creates an integer spinner with 0 as min, 100 as max and 10 as initial 
// value and 10 as amount to increment or decrement by, per step
Spinner<Integer> spinner2 = new Spinner<>(0, 100, 10, 10);
Run Code Online (Sandbox Code Playgroud)

带有" 整数 "微调器和" "微调器的结果示例

在此输入图像描述

旋转器是一个单行文本字段控制,以允许用户从这样的值的有序序列中选择一个数字或者一个对象的值.旋转器通常提供一对微小的箭头按钮,用于单步执行序列的元素.键盘的向上箭头/向下箭头键也循环显示元素.也可以允许用户直接在微调器中键入(合法)值.虽然组合框提供类似的功能,但有时候首选旋转器是因为它们不需要可以模糊重要数据的下拉列表,还因为它们允许从最大值回送到最小值等功能(例如,从最大正整数到0).

有关Spinner控件的更多详细信息


ubu*_*oid 6

TextField text = new TextField();

text.textProperty().addListener(new ChangeListener<String>() {
    @Override
    public void changed(ObservableValue<? extends String> observable,
            String oldValue, String newValue) {
        try {
            Integer.parseInt(newValue);
            if (newValue.endsWith("f") || newValue.endsWith("d")) {
                manualPriceInput.setText(newValue.substring(0, newValue.length()-1));
            }
        } catch (ParseException e) {
            text.setText(oldValue);
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

if子句对于处理由Int.parseInt()正确解析的输入(如0.5d或0.7f)非常重要,但不应出现在文本字段中.

  • 活泉?从什么时候开始正确解析了Integer.parseInt()?它抛出一个java.lang.NumberFormatException:对于输入字符串:"0.5d"(正如预期的那样,因为它不是整数) (9认同)