【问题标题】:How in Java I can create a field that can accept only digits and once dot?如何在 Java 中创建一个只能接受数字和一次点的字段?
【发布时间】:2015-05-11 12:22:17
【问题描述】:

我在网上找遍了所有我尝试过的东西都没有奏效......

我发现我可以使用一些 JTextFormatterField 但它不起作用。

然后我发现我可以将 DocumentFilter 与正则表达式一起使用,而我做了什么:

JTextField jFormattedTextFieldMoneyToConvert = new JTextField();
    ((AbstractDocument) jFormattedTextFieldMoneyToConvert.getDocument()).setDocumentFilter(new DocumentFilter(){
        Pattern regEx = Pattern.compile("^\\d+\\.?\\d*$");

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            Matcher matcher = regEx.matcher(text);
            if (!matcher.matches()) {
                return;
            }
            super.replace(fb, offset, length, text, attrs);
        }
    });

但它不起作用...它只接受数字。我希望它也接受点。而且我还需要它不要以点开头,也不要以点结尾。

我做错了什么?

【问题讨论】:

  • but it doesn't work... 请定义...
  • 抱歉,我编辑了我的问题
  • I also need it to not to start with a dot and not to end with a dot. - 表达式为^\d+(\.\d+)?$,即至少一位数字可选地后跟一个点,并且至少再增加一位数字。

标签: java regex swing jtextfield documentfilter


【解决方案1】:

这可能是最简单的代码:

if (text.matches("\\d+(\\.\\d+)?"))

如果有一个点,它后面必须跟一些数字。如果你也想允许一个点然后 no 数字,请将 + 更改为 *

if (text.matches("\\d+(\\.\\d*)?"))

请注意,对于String#matches(),前导/尾随^/$ 不是必需的,因为它们是隐含的,因为必须匹配整个字符串matches() 返回true

不允许前导数字也变得更棘手,因为正则表达式 (\d+)?(\.\d*) 匹配空白字符串,所以你需要一个替代:

if (text.matches("\\d+(\\.\\d*)?|\\.\\d+"))

或消极的展望:

if (text.matches("(?!$)\\d*(\\.\\d*)?"))

小看头断言开始后的下一个位置不是结束(即输入不为空)。

【讨论】:

    【解决方案2】:

    我有一个similar problem a while back。问题不在于正则表达式,而是我对过滤器如何工作的误解。我的假设,就像你的假设是 String text 传递给 replace 方法,是整个字符串,而实际上它只是被键入的字符。类似的讨论here

    虽然@Bohemian's regex kung-fu 可能是您在匹配正则表达式方面寻找的东西(我不知道,这不是我的强项),但问题(假设)可以通过获得来解决整个文档文本,然后尝试匹配 that,即

    String completeText = fb.getDocument().getText(0, fb.getDocument().getLength());
    

    “而且我还需要它不以点开头,也不以点结尾”

    从逻辑上考虑一下。为每个字符输入调用过滤器。但是你不想以. 结尾,但你想在中间的某个地方允许.。最后不允许. 否定. 的可能性,因为您需要在下一个数字之前的最后输入.

    如果用户留下一个悬空的.,您可能只需要编写一个焦点侦听器来添加 0 或在字段失去焦点时删除 .


    更新:完整示例

    import java.awt.*;
    import javax.swing.*;
    import javax.swing.text.*;
    
    public class FilterDemo {
    
        public FilterDemo() {
            JFrame frame = new JFrame();
            frame.setLayout(new GridBagLayout());
            frame.setSize(300, 300);
            frame.add(createFilteredField());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
    
        }
    
        private JTextField createFilteredField() {
            JTextField field = new JTextField(20);
            AbstractDocument document = (AbstractDocument) field.getDocument();
            final int maxCharacters = 10;
            document.setDocumentFilter(new DocumentFilter() {
                @Override
                public void replace(FilterBypass fb, int offs, int length,
                        String str, AttributeSet a) throws BadLocationException {
    
                    String text = fb.getDocument().getText(0,
                            fb.getDocument().getLength());
                    text += str;
                    if (text.matches("^\\d+\\.?\\d*$")) {   //  "^[0-9]+[.]?[0-9]{0,}$"
                        super.replace(fb, offs, length, str, a);
                    } else {
                        Toolkit.getDefaultToolkit().beep();
                    }
    
                }
    
                @Override
                public void insertString(FilterBypass fb, int offs, String str,
                        AttributeSet a) throws BadLocationException {
    
                    String text = fb.getDocument().getText(0,
                            fb.getDocument().getLength());
                    text += str;
                    if (text.matches("^\\d+\\.?\\d*$")) {
                        super.insertString(fb, offs, str, a);
                    } else {
                        Toolkit.getDefaultToolkit().beep();
                    }
                }
            });
            return field;
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new FilterDemo();
                }
            });
        }
    }
    

    【讨论】:

    • 你说得对。我怎么能用最后的点来做呢?
    • 您是否尝试过使用您当前使用的正则表达式?看起来它应该可以工作,就像你做我提到的修复一样记录
    • 是的,fb.getDocument().getText(0, fb.getDocument().getLength());为空... fb.getDocument().getLength() 返回 0
    • 那你做错了什么。查看更新将完整程序
    • 是的,所以我忘记了新字符串/字符实际上还没有插入到文档中的事实。这就是为什么需要在匹配之前连接:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多