Java JTextField,使用文档过滤器过滤整数和句点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24844559/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:10:26  来源:igfitidea点击:

JTextField, using Document Filter to filter integers and periods

javaswingjtextfielddocumentfilter

提问by Joao Bastos

EDIT - added at then end of the post the answer we were able to achieve

编辑 - 在帖子末尾添加了我们能够实现的答案

This is my first post in SO, so i hope i can ask everything right!

这是我在 SO 中的第一篇文章,所以我希望我能问对的一切!

I searched and didn't quite find a answer to my question despite similar questions being posted, so i hope this isn't a repost.

尽管发布了类似的问题,但我搜索并没有完全找到我的问题的答案,所以我希望这不是转帖。

This is what a i got, a small application that uses JTextFieldto receive user's input and on top of that i have a DocumentFilterso the user can only input integers and a period in order to receive values that represent weight.

这就是ai得到的,一个JTextField用于接收用户输入的小应用程序,最重要的是我有一个DocumentFilter所以用户只能输入整数和一个句点来接收表示重量的值。

My problem is, with my DocumentFilterI'm not being able to filter "copy pasted" text and i can't filter a selected text removal.

我的问题是,我DocumentFilter无法过滤“复制粘贴”文本,也无法过滤选定的文本删除。

Here is the code for the Filter

这是过滤器的代码

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

/**
* The Class IntAndDotFilter.
*/
public class IntAndDotFilter extends DocumentFilter {

/** The period counter. */
private int periodCounter = 0;

/** The number counter. */
private int numberCounter = 0;

private boolean canRemove = true;

public void setCanRemove(boolean canRemove) {
    this.canRemove = canRemove;
}

@Override
public void replace(FilterBypass fb, int offset, int length, String text,
        AttributeSet attrs) throws BadLocationException {

    if (periodCounter == 0) { // If there is no . on the text
        if (text.matches("\.")) { // Checks if the input is a dot
            super.replace(fb, offset, length,
                    text.replaceAll("[^0-9.]", ""), attrs);
            periodCounter++; // If it is, inserts it and saves that info
        } else {
            super.replace(fb, offset, length,
                    text.replaceAll("[^0-9]", ""), attrs);
            // If not, checks if the input is a digit
            // and inserts if it is
        }
    } else { // If there is already a .
        if (text.matches("\.")) { // Checks if the input is another .
            super.replace(fb, offset, length,
                    text.replaceAll("[^0-9]", ""), attrs);
            // If it is, filters so that cannot be more than one .
        } else {
            if (text.matches("[0-9]")) { // Checks if it's a digit
                if (numberCounter != 2) {
                    super.replace(fb, offset, length,
                            text.replaceAll("[^0-9]", ""), attrs);
                    numberCounter++;
                    // If yes, and if that is only the second one (0.00)
                    // inserts and
                    // saves the info that there are digits after the 1st .
                    // for removal purposes
                } else {
                    super.replace(fb, offset, length,
                            text.replaceAll(".", ""), attrs);
                    // if it is the third+ digit after . , doesn't allow the
                    // input
                }
            } else {
                super.replace(fb, offset, length, text.replaceAll(".", ""),
                        attrs);
                // Not being a digit, doesn't allow the
                // insertion of the given input
            }
        }
    }
}

@Override
public void remove(FilterBypass fb, int offset, int length)
        throws BadLocationException {

    if (canRemove) {
        if (periodCounter == 1) { // If there is a . in the text
            if (numberCounter != 0) { // and If there are digits after the .
                numberCounter--; // It means you'r removing a digit, so it
                                    // saves
                                    // that info
                super.remove(fb, offset, length); // And removes it
            } else { // If there are no digits it means you'r removing a .
                periodCounter--; // It saves that info allowing a new . to
                                    // be
                                    // inserted
                super.remove(fb, offset, length); // and removes it
            }
        } else { // If there is no . in the text there are no problems
            super.remove(fb, offset, length); // so it just removes whatever
                                                // there is (digit)
        }
    } else {

    }
}
}

the insertString method does the same has the replace method so i left it out, but in the application it's implemented.

insertString 方法与 replace 方法相同,所以我省略了它,但在应用程序中它已实现。

Thanks in advance for your time!

在此先感谢您的时间!

EDIT - Plus it now has a filter to restrain the height input too

编辑 - 另外它现在也有一个过滤器来限制高度输入

public class IntAndDotFilter extends DocumentFilter {

/** The Constant _maxCharacters. */
private static final int _maxCharacters = 10;

/** The _is weight. */
private Boolean _isWeight = null;


public IntAndDotFilter(Boolean isWeight) {
    super();
    _isWeight = isWeight;
}

public void replace(FilterBypass fb, int offset, int length, String string,
        AttributeSet attr) throws BadLocationException {

    String text = fb.getDocument().getText(0, fb.getDocument().getLength());
    text += string;

    if (_isWeight) {
        if ((fb.getDocument().getLength() + string.length() - length) <= _maxCharacters
                && text.matches("^[1]?[0-9]{1,2}([.][0-9]{0,2})?$")) {
            super.replace(fb, offset, length, string, attr);
        } else {
            Toolkit.getDefaultToolkit().beep();
        }
    } else {
        if ((fb.getDocument().getLength() + string.length() - length) <= _maxCharacters
                && text.matches("^([1]([.][0-9]{0,2})?)|([2]([.][0-5]?)?)$")) {
            super.replace(fb, offset, length, string, attr);
        } else {
            Toolkit.getDefaultToolkit().beep();
        }
    }
}

@Override
public void remove(FilterBypass fb, int offset, int length)
        throws BadLocationException {

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

    if (_isWeight) {
        if (text.matches("^[1]?[0-9]{1,2}([.][0-9]{0,2})?$")) {
            super.remove(fb, offset, length);
        } else {
            Toolkit.getDefaultToolkit().beep();
        }
    } else {
        if (text.matches("^([1]([.][0-9]{0,2})?)|([2]([.][0-5]?)?)$")) {
            super.remove(fb, offset, length);
        } else {
            Toolkit.getDefaultToolkit().beep();
        }
    }
}

采纳答案by Paul Samsotha

You're making the filtering more complicated than it has to be. For inserting (if the code is same is replace), you are not able to enter probably because of the \\.check. You will only be able to paste a period, as that's what you are checking for. As for the remove, the suggestion below will apply.

你让过滤变得比它必须的更复杂。对于插入(如果代码相同则替换),您可能因为\\.检查而无法输入。您将只能粘贴一个句点,因为这是您要检查的内容。至于删除,下面的建议将适用。

To simplify things, you should just get the entire text of the document, then use regex to check if the entire document string matches the regex. It's much simpler than what you are trying to do. You can get a good explanation of the filtering process here.

为简化起见,您应该只获取文档的整个文本,然后使用正则表达式检查整个文档字符串是否与正则表达式匹配。这比您尝试做的要简单得多。您可以在此处获得有关过滤过程的详细说明。

Here's an example, using just insertString and replace. For the remove, it's no different, just get the text, and check if it matches a regex. I took part of the example from the answer in the link above. The scenario was that the OP wanted max charcters, along with only one decimal place allowed. That's what the regex matches. But could also match anything as you're typing or inserting such as 0000.00.0

这是一个示例,仅使用 insertString 和 replace。对于删除,它没有什么不同,只需获取文本,然后检查它是否与正则表达式匹配。我从上面链接中的答案中选取了一部分示例。场景是 OP 需要最大字符数,并且只允许一位小数。这就是正则表达式匹配的内容。但也可以在您键入或插入时匹配任何内容,例如0000.00.0

import java.awt.GridBagLayout;
import java.awt.Toolkit;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;

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);

    }

    public JTextField createFilteredField() {
        JTextField field = new JTextField();
        AbstractDocument document = (AbstractDocument) field.getDocument();
        final int maxCharacters = 10;
        document.setDocumentFilter(new DocumentFilter() {
            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 ((fb.getDocument().getLength() + str.length() - length) <= maxCharacters
                        && text.matches("^[0-9]+[.]?[0-9]{0,1}$")) {
                    super.replace(fb, offs, length, str, a);
                } else {
                    Toolkit.getDefaultToolkit().beep();
                }
            }

            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 ((fb.getDocument().getLength() + str.length()) <= maxCharacters
                        && text.matches("^[0-9]+[.]?[0-9]{0,1}$")) {
                    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();
            }
        });
    }
}