2013-03-01 88 views
6

我正在使用JavaFX 2.2項目,使用TextField控件時出現問題。我想限制用戶輸入到每個TextField的字符,但是我找不到一個屬性或類似maxlength的東西。同樣的問題存在搖擺,並用this方式解決。如何解決它的JavaFX 2.2?JavaFX 2.2 TextField maxlength

+1

對JavaFX而言,不具備開箱即用的基本功能不太好。 – 2016-06-30 13:00:30

回答

8

這是一個更好的方式做一個普通的文本字段的工作:

public static void addTextLimiter(final TextField tf, final int maxLength) { 
    tf.textProperty().addListener(new ChangeListener<String>() { 
     @Override 
     public void changed(final ObservableValue<? extends String> ov, final String oldValue, final String newValue) { 
      if (tf.getText().length() > maxLength) { 
       String s = tf.getText().substring(0, maxLength); 
       tf.setText(s); 
      } 
     } 
    }); 
} 

完美的工作,除了那個撤消錯誤。

+3

當心:通知期間修改發送方的狀態通常是一個壞主意 - 你可能會難以跟蹤的副作用(撤消錯誤可能是這樣一個不必要的副作用,雖然我沒有挖進去) – kleopatra 2015-10-19 15:23:04

+0

@ceklock請不要介意,如果我要求解釋,會發生什麼情況:::: String s = tf.getText()。substring(0,maxLength);被替換爲s = oldValue;因爲我很難理解它! – 2017-02-06 16:36:44

6

你可以做同樣的事情到這裏的方法描述:http://fxexperience.com/2012/02/restricting-input-on-a-textfield/

class LimitedTextField extends TextField { 

    private final int limit; 

    public LimitedTextField(int limit) { 
     this.limit = limit; 
    } 

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

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

    private void verify() { 
     if (getText().length() > limit) { 
      setText(getText().substring(0, limit)); 
     } 

    } 
}; 
+0

首先檢查並替換文本不是很好嗎? – keuleJ 2013-03-01 15:41:38

+0

這是可能的,但對於短期樣本,邏輯將變得太複雜。 – 2013-03-01 16:34:39

+0

爲了使它工作,我添加了一個0參數構造函數和一個限制屬性的setter方法。謝謝你。 – 2013-03-01 18:01:22

3

完整的代碼我用來解決我的問題是下面的代碼。我擴展了像Sergey Grinev那樣的TextField類,並且我添加了一個空構造函數。要設置最大長度,我添加了一個setter方法。我首先檢查並替換TextField中的文本,因爲我想禁止插入多於maxlength字符,否則將在TextField的末尾插入maxlength + 1字符,並刪除TextField的第一個字符。

package fx.mycontrols; 

public class TextFieldLimited extends TextField { 
    private int maxlength; 
    public TextFieldLimited() { 
     this.maxlength = 10; 
    } 
    public void setMaxlength(int maxlength) { 
     this.maxlength = maxlength; 
    } 
    @Override 
    public void replaceText(int start, int end, String text) { 
     // Delete or backspace user input. 
     if (text.equals("")) { 
      super.replaceText(start, end, text); 
     } else if (getText().length() < maxlength) { 
      super.replaceText(start, end, text); 
     } 
    } 

    @Override 
    public void replaceSelection(String text) { 
     // Delete or backspace user input. 
     if (text.equals("")) { 
      super.replaceSelection(text); 
     } else if (getText().length() < maxlength) { 
      // Add characters, but don't exceed maxlength. 
      if (text.length() > maxlength - getText().length()) { 
       text = text.substring(0, maxlength- getText().length()); 
      } 
      super.replaceSelection(text); 
     } 
    } 
} 

裏面的FXML文件我增加了進口(的該TextFieldLimited類是現有的包裝)上的文件的頂部,代之以自定義TextFieldLimited的文本字段標籤。

<?import fx.mycontrols.*?> 
. 
. 
. 
<TextFieldLimited fx:id="usernameTxtField" promptText="username" /> 

控制器類內部,

在頂部(屬性聲明)


@FXML
private TextFieldLimited usernameTxtField;

initialize方法內,
usernameTxtField.setLimit(40);

就是這樣。

+0

你能解釋一下,爲什麼你在設置或替換一些文本之前使用'getText' **?聽起來對我錯了。你是否用C&P測試了這個? – Hardcoded 2013-05-27 09:27:39

+0

我想將新的字符輸入附加到TextField中,**僅**如果文本的長度不會超過maxlength。這就是爲什麼我第一次檢查長度是否達到maxlength,然後追加新字符。當用戶點擊刪除或退格時,存在錯誤的部分。我更新了代碼。此外,我更新replaceSelection()方法,以防止用戶粘貼文本的長度,除了現有的文本,超過maxlength字符超過maxlength。我測試過,它工作正常。 – 2013-05-27 20:01:13

1

我用一個簡單的方法來限制雙方的字符數,並迫使數字輸入:

public TextField data; 
public static final int maxLength = 5; 

data.textProperty().addListener(new ChangeListener<String>() { 
    @Override 
    public void changed(ObservableValue<? extends String> observable, 
      String oldValue, String newValue) { 
     try { 
      // force numeric value by resetting to old value if exception is thrown 
      Integer.parseInt(newValue); 
      // force correct length by resetting to old value if longer than maxLength 
      if(newValue.length() > maxLength) 
       data.setText(oldValue); 
     } catch (Exception e) { 
      data.setText(oldValue); 
     } 
    } 
}); 
+0

不會downvote,但如果你輸入上面的'maxLength'並嘗試使用系統默認撤消這種方法會導致'java.lang.IndexOutOfBoundsException'。 – Neeko 2013-10-04 14:17:40

+0

好一點 - 我還使用這樣的技術現在:http://stackoverflow.com/questions/13562712/how-to-disable-the-default-context-menu-on-a-text-field – hemisphire 2013-10-08 21:22:49

+0

我關於這個Undo錯誤的問題開了我自己的問題。請參閱http://stackoverflow.com/questions/19184305/limiting-character-count-of-javafx-textfield-causes-indexoutofbounds-on-undo獲取相當好的解決方案。 – Neeko 2013-10-09 13:22:13

0

下面的代碼將重新定位光標,以便用戶不會意外地覆蓋其輸入。

public static void setTextLimit(TextField textField, int length) { 
    textField.setOnKeyTyped(event -> { 
     String string = textField.getText(); 

     if (string.length() > length) { 
      textField.setText(string.substring(0, length)); 
      textField.positionCaret(string.length()); 
     } 
    }); 
} 
1

此方法讓TextField完成所有處理(複製/粘貼/撤消安全)。 不要求擴展課程。 並允許您設定在每次更改 (將其推到邏輯,或回到之前的值,甚至修改它)後如何處理新文本。

// fired by every text property change 
textField.textProperty().addListener(
    (observable, oldValue, newValue) -> { 
    // Your validation rules, anything you like 
     // (! note 1 !) make sure that empty string (newValue.equals("")) 
     // or initial text is always valid 
     // to prevent inifinity cycle 
    // do whatever you want with newValue 

    // If newValue is not valid for your rules 
    ((StringProperty)observable).setValue(oldValue); 
     // (! note 2 !) do not bind textProperty (textProperty().bind(someProperty)) 
     // to anything in your code. TextProperty implementation 
     // of StringProperty in TextFieldControl 
     // will throw RuntimeException in this case on setValue(string) call. 
     // Or catch and handle this exception. 

    // If you want to change something in text 
     // When it is valid for you with some changes that can be automated. 
     // For example change it to upper case 
    ((StringProperty)observable).setValue(newValue.toUpperCase()); 
    } 
); 

爲了您的情況,只需在裏面添加這個邏輯。完美的作品。

// For example 10 characters  
    if (newValue.length() >= 10) ((StringProperty)observable).setValue(oldValue); 
6

隨着java8u40我們得到了一類新的TextFormatter:它的主要職責之一是之前提供一個勾成文本輸入的任何變化它就會comitted的內容。在那個鉤子我們可以accept/rejec t甚至改變建議的變化。

OP's self-answer解決的要求是

  • 規則:限制文本的長度短於n個字符
  • 修改:如果違反規則,保持最後n個字符的輸入

    // here we adjust the new text 
    TextField adjust = new TextField("scrolling: " + len); 
    UnaryOperator<Change> modifyChange = c -> { 
        if (c.isContentChange()) { 
         int newLength = c.getControlNewText().length(); 
         if (newLength > len) { 
          // replace the input text with the last len chars 
          String tail = c.getControlNewText().substring(newLength - len, newLength); 
          c.setText(tail); 
          // replace the range to complete text 
          // valid coordinates for range is in terms of old text 
          int oldLength = c.getControlText().length(); 
          c.setRange(0, oldLength); 
         } 
        } 
        return c; 
    }; 
    adjust.setTextFormatter(new TextFormatter(modifyChange)); 
    
    :文本,並刪除在其開始

多餘的字符使用的TextFormatter,這可能等來實現

旁白:

  • 修改屬性,一邊聽它的變化可能會導致意想不到的副作用
  • 所有建議的解決方案的關鍵級事件被破壞(他們不能處理粘貼/程序化的變化
-1

我有這樣的代碼,它只允許數字並限制Javafx中文本字段的輸入長度。

// Event handler for inputPrice 
    inputPrice.setOnAction(event2 -> { 

      // Obtain input as a String from text field 
      String inputPriceStr = inputPrice.getText(); 

      // Get length of the String to compare with max length 
      int length = inputPrice.getText().length(); 

      final int MAX = 10; // limit number of characters 

      // Validate user input allowing only numbers and limit input size 
      if (inputPriceStr.matches("[0-9]*") && length < MAX) { 

       // your code here 
      }});