2017-08-31 39 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

我改變了答案,嘗試使用此代碼 –

相關問題