• JTextField限制输入长度的完美解决方案


        关于JTextField限制输入字符长度的问题,因为没提供现成的api,所以我们得自己动手,来实现这个功能,网上也有很多这样的资料,大多是在JTextField的Document的insertString方法中动手脚,比较当前文本框的字符长度和最大长度,如果输入不涉及中文,该方法也堪称完美了。
        细心的童鞋可能会发现,在swing里输入中文,有的是下方弹出一个小方框,显示当前输入的字母;有的是直接将这些字母显示在了文本输入框里,打完一个字词时,将这些字母清除掉,再将中文显示上去。这两种不同的显示方式取决于System.getProperty("java.awt.im.style")的值是不是"below-the-spot",如果是,输入框下方就显示一个小窗口(如果为null好像也是这样),这种情况下,上面的解决办法也没有问题;如果不是,即字母显示在文本输入框中,那么在输入字符接近或达到最大长度时,会出现吃掉前面的字符的情况
        此问题的原因在于,在输入中文时,将键入的字母(暂且称之为“临时字母”吧)打印在了输入框内,假如是j,按第二个字母时(假如是i),会把之前的临时字母(j)删除,再用insertString插入ji,再输入n时,把ji删除,再插入jin,JTextField的公共方法是无法区分临时字母的,如果插入ji时达到了长度上限,插入失败,再输入n,删除ji,此时ji并未插入,所以就删除了左边的字符,此时就出现了吃掉左边字符的问题。

    接下来说解决办法:
    重写Document里的方法

    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
     if (a == null) {
      int allowCount = maxLength - getLength();
      if (allowCount > 0) {
       if (allowCount < str.length())
        str = str.substring(0, allowCount);
      } else
       return;
     }
     super.insertString(offs, str, a);
    }

        经调试跟踪,插入临时字母时AttributeSet a都不是null,而输入英文或中文上屏时,a都为空,所以临时字母能够正常插入,删除时,就不会拿正常输入的字符当替死鬼了。
    到此,问题已经基本解决了,只是到了长度上限,还能敲入临时字母,虽然切换输出法、失去焦点啥的,临时字母会自动被删除(所以说基本没什么问题了,除非你不是根据鼠标键盘操作去getText,要不getText是不会获取到临时字母的),但如果有点完美主义的话,心里还是有点不舒服,为啥就不能让它在达到最大长度时,连临时字母也不能输入了?
        因为临时字母的删除再插入,在insertString、remove等处已经发生了,又不方便跟正常删除插入进行区分,所以往上找,找到了输入法事件处理的代码,在此处就能比较根本地解决问题了

    private int composedLen;
    @Override
    protected void processInputMethodEvent(InputMethodEvent e) {
     if (e.getID() == InputMethodEvent.INPUT_METHOD_TEXT_CHANGED) {
      if (e.getCommittedCharacterCount() == 0) {
       AttributedCharacterIterator aci = e.getText();
       if (getDocument().getLength() - composedLen >= maxLength) {
        e.consume();
        composedLen = 0;
       } else
        composedLen = aci != null ? aci.getEndIndex()
          - aci.getBeginIndex() : 0;
      } else
       composedLen = 0;
     }
     super.processInputMethodEvent(e);
    }

        在JTextField里重写processInputMethodEvent方法,并定义一个composedLen变量,用来记录文本中的临时字母的长度,文本长度减去临时字母的长度,就得到了真正输入的字符的长度了,如果这个长度大于等于上限,就消耗掉这个事件(e.consume()),让它失效。介绍下里面的方法,e.getCommittedCharacterCount()得到的是提交的字符数,也就是中文上屏时,中文的字符个数,aci.getEndIndex() - aci.getBeginIndex()得到的是文本的长度,可能是上屏的中文,也可能是临时字母。

    如果你对我用insertString里的AttributeSet a是否为null作为判断依据有所质疑的话(JDK升级后,这规则还有效吗?),也可以把composedLen传到insertString里,作为判断依据。

    OK,大功告成了,虽然没写多少内容,但找出问题和解决问题的过程,还是花了我一些时间的,有点啰嗦,就不写了

  • 相关阅读:
    Spring入门之一-------实现一个简单的IoC
    SpringBoot+SpringSecurity之多模块用户认证授权同步
    SpringBoot+SpringSecurity之如何forword到登录页面
    SpringBoot实现OAuth2认证服务器
    SpringBoot安全认证Security
    SpringBoot的ApplicationRunner和CommandLineRunner
    SpringBoot通过ApplicationArguments获取args
    安利demo
    多路canvas的mapbox gl
    复合canvas叠加显示
  • 原文地址:https://www.cnblogs.com/trytocatch/p/jtextfield_maxlength.html
Copyright © 2020-2023  润新知