2017-08-31 74 views
1

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

我发现一个solution for integers埠我无法设法使用它的双打。我应该写什么,而不是"\\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]", "")); 
     } 
    } 
}); 
+0

不要使用侦听器;文本属性的其他观察者将在恢复之前看到无效输入。改用'TextFormatter'。 –

回答

4

使用监听器,并恢复到有效的值,如果无效值是由用户输入将工作的方法,但是如果你对文本字段的textProperty其他听众它可以创造的问题。那些听众将观察无效值和有效值,因此他们必须知道过滤掉任何无效值。

更好的方法是使用TextFormatter。该TextFormatter可以做两两件事:

  1. 定义一个“过滤器”,它可以否决或修改,到TextField的文本所做的任何更改
  2. 定义一个‘转换器’,它定义了如何转换文本与任何特定类型的值(例如Double)在您的案例中。

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

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

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",如果这适合于语言环境)或科学记数法表示("6.022E23"等),并强制执行最小或最大值等。您甚至可以执行诸如修改该更改,以便如果用户在文本的任何位置键入-,则只需翻转该号码的符号即可。 (请参阅TextFormatter.Change documentation这种功能。)

请注意,您可以直接从格式化程序获取并设置double值(由转换程序提供),该格式化程序具有ObjectProperty<Double> valueProperty()。所以你可以做像

// 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。第二个文本字段就在那里,以便您可以看到将焦点移动到不同控件的效果(如果值已更改,则会“提交”该值并调用文本格式器上的侦听器;如果用户出现类似的情况按下进入)。

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

} 
1

您可以使用Double.parseDouble Double Javadoc。这会为你解析,而不是写你自己的双重验证。然后您可以检查数字格式异常或空指针异常。

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

感谢您的回答,但我试图**强制**用户只输入双值。我想避免管理无效输入。 – Robb1

+0

只有强制用户输入双精度的方法是检测无效输入。在正则表达式匹配上执行if或将上面的代码拉入到返回true或false的testDouble方法之间没有区别。 –

+1

“只能强制用户输入双精度的方法是检测无效输入。”不对。例如,您可以覆盖各种'insert'方法,或者使用'TextFormatter'。 –

1

您可以在双打上使用java正则表达式,并用数字替换非数字字符。在你必须指定整数部分允许的位数,例如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(); 
     } 
    } 
}); 
+0

感谢您的回答,但是如果我尝试在第二个'。'输入99.99.'时出现错误(此外输入更改为9999)。任何想法如何解决这个问题? – Robb1

+0

我改变了答案,尝试使用此代码 –