2013-03-01 113 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 
      }});