【问题标题】:Strict 24-hour time in JFormattedTextFieldJFormattedTextField 中的严格 24 小时制时间
【发布时间】:2012-06-18 13:23:03
【问题描述】:

我正在尝试创建一个只接受 24 小时时间的 JFormattedTextField。

我非常接近解决方案,但有一种情况下以下代码示例不起作用。

如果您输入时间“222”并从字段中更改焦点,则时间将更正为“2202”。我希望它只接受完整的 4 位数 24 小时时间。这段代码几乎在所有情况下都能按我的意愿工作,除了我刚才提到的那个。有什么建议吗?

    public static void main(String[] args) throws ParseException {
        DateFormat dateFormat = new SimpleDateFormat("HHmm");
        dateFormat.setLenient(false);

        DateFormatter dateFormatter =  new DateFormatter(dateFormat);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JFormattedTextField textField = new JFormattedTextField(dateFormatter);
        frame.add(textField, BorderLayout.NORTH);

        frame.add(new JTextField("This is here so you can change focus."), BorderLayout.SOUTH);
        frame.setSize(250, 100);
        frame.setVisible(true);
    }

【问题讨论】:

  • 简单的解决方法是使用JTextField,并使用DocumentFilter :-) 对于DocumentFilter,您可以查看example
  • 不正确,可能是 02:22 或 22:02
  • 如果您使用的是 SimpleDateFormat,您可能会不走运。来自 Javadoc:“对于解析,模式字母的数量被忽略,除非需要分隔两个相邻的字段。”它将前两位数字解析为小时字段,因此它知道剩余数字必须是分钟字段。
  • 啊哈,太真实了,做一件事然后在FocusLost上检查长度如果小于4,然后给用户一个JOptionPane看,或者不要让如果长度小于 4,此组件将失去焦点 :-)

标签: java swing simpledateformat jformattedtextfield


【解决方案1】:

正如其他人所提到的,您最好的选择可能是验证输入字符串的长度。我首选的方法是继承 SimpleDateFormat 以将所有解析逻辑保存在一个地方:

public class LengthCheckingDateFormat extends SimpleDateFormat {

  public LengthCheckingDateFormat(String pattern) { super(pattern); }

  @Override
  public Date parse(String s, ParsePosition p) {
    if (s == null || (s.length() - p.getIndex()) < toPattern().length()) {
      p.setErrorIndex(p.getIndex());
      return null;
    }
    return super.parse(s, p);
  }
}

【讨论】:

  • 或者更可重用:为标准 Java 格式创建一个装饰器,仅在可以解析整个输入字符串时才指示解析成功(ParseAllFormat),因此可以重用
  • 很好的答案,我喜欢覆盖 SimpleDateFormat 而不是添加焦点侦听器。我对您的代码所做的一项更改不是抛出 ParseException,而是根据 SimpleDateFormat 解析方法 JavaDoc 返回 null。
  • @Robin 好点,这可能会被更改为包装通用格式化程序以进行相同的检查。
  • @FuryComptuers 很好的捕捉 - 单参数解析抛出异常,多参数返回 null。更改了代码以反映这一点,并在检查长度时考虑解析位置。
  • @Alex 返回null 时,您可能还应该在ParsePosition 中设置错误索引
【解决方案2】:

我想知道DateFormatter 似乎“几乎”可以解决所有问题。

因此,为什么不重写其方法一,该方法进行最终验证和格式化,以将所有输入的太短的Strings 视为空String。

        DateFormatter dateFormatter = new DateFormatter(dateFormat) {
            @Override
            public Object stringToValue(String text) throws ParseException {
                if(!getFormattedTextField().hasFocus())
                    if (text.length() != 4) {
                        return null;
                    }
                return super.stringToValue(text);
            }            
        };

编辑:

正如@nIcE cOw 所建议的,最简单的方法是在失去焦点时提供它:

    final JFormattedTextField textField = new JFormattedTextField(dateFormatter);
    textField.addFocusListener(new FocusAdapter() {
        @Override
        public void focusLost(FocusEvent e) {
            super.focusLost(e);
            if(textField.getText().length() != 4)
                textField.setText("");
        }
    });

【讨论】:

  • 我会说这种方法经得起时间的考验:-)
  • @nIcEcOw 我会说这会导致JFormattedTextField 的意外行为。通常,当值无效时,它会恢复为focusLost 上的先前有效值。但是在这里您是手动修改内容...。并且不确定当您使用无效值按 ENTER 时会发生什么。所以我强烈建议去接受 Alex 发布的答案
  • @Robin ENTER 默认不做任何事情。顺便说一句:我找到了DateFormatter 的方法,我在答案中添加了一个涉及它的解决方案,遗憾的是它也依赖于文本字段的焦点,因为我不确定如何检测调用的正确时间长度测试作为方法stringToValue 在任何键输入上调用。综上所述,我自己会接受 Alex 的回答(+1),因为它不那么老套。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 2021-11-27
  • 2014-11-20
  • 1970-01-01
相关资源
最近更新 更多