且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JTextField限制字符数量输入并仅接受数字

更新时间:2023-02-24 18:29:53

你走在正确的轨道上,除了你想要使用DocumentFilter 而不是实现自己的文档。

You're on the right track, except you will want to use a DocumentFilter instead of implementing your own document.

MDP的博客有许多优秀的例子(包括限制长度和字符类型)。

MDP's Weblog has a number of excellent examples (including limiting the length and character type).

现在问题,您可以创建级联过滤器,您可以将一系列过滤器链接在一起。

Now to the your question, you could create cascading filter, where you could chain a series of filters together.

这个允许你依次调用每个过滤器。

This would allow you to call each filter in turn.

public class ChainableFilter extends DocumentFilter {

    private List<DocumentFilter> filters;
    private AttributeSet attr;

    public ChainableFilter() {
        filters = new ArrayList<DocumentFilter>(25);
    }

    public void addFilter(DocumentFilter filter) {
        filters.add(filter);
    }

    public void removeFilter(DocumentFilter filter) {
        filters.remove(filter);
    }

    public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.insertString(fb, offset, string, attr);
        }
    }        

    public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.remove(fb, offset, length);
        }
    }

    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        for (DocumentFilter filter : filters) {
            filter.replace(fb, offset, length, text, attrs);
        }
    }

}

现在它如果过滤器实际上可以告诉链条它是否会改变文档会很好,但我会把它留给你

Now it would be nice if filter could actually tell the chain if it altered the document at all, but I'll leave that up to you

UPDATED

你所做的事与 DocumentFilters 工作的基本概念基本相同。好处是,你不是将自己限制在 PlainDocument ,理论上你可以将它应用于 JTextPane JEditorPane

The basic concept between what you've done and how DocumentFilters work is pretty much the same. The benefit is, you're not limiting your self to a PlainDocument, you could, in theory, apply it to a JTextPane or JEditorPane.

过滤器链的基本思路很简单。

The basic idea of the filter chain is simple.

ChainableFilter chainableFilter = new ChainableFilter();
chainableFilter.addFilter(new RestrictedLengthFilter()); // User supplied filter 
chainableFilter.addFilter(new NumericFilter()); // User supplied filter 

((AbstractDocument)textField.getDocument()).setDocumentFilter(chainableFilter);

至于实际过滤器,我会查看我之前发布的链接。尽管

As for the actual filters, I'd check out the link I posted earlier. You're on the right track with your ideas though

更新

SizeFilter sizeFilter = new SizeFilter(12);
NumberFilter numFilter = new NumberFilter();
ChainableFilter chainFilter = new ChainableFilter();
chainFilter.addFilter(sizeFilter);
chainFilter.addFilter(numFilter);

JTextField field = new JTextField();
((AbstractDocument) field.getDocument()).setDocumentFilter(chainFilter);



    public class NumberFilter extends DocumentFilter {

        private int decimalPrecision = 2;
        private boolean allowNegative = false;

        public NumberFilter() {
        }

        public NumberFilter(int decimals, boolean negatives) {
            decimalPrecision = decimals;
            allowNegative = negatives;
        }

        protected boolean accept(FilterBypass fb, int offset, String str) throws BadLocationException {
            boolean accept = true;    
            int length = fb.getDocument().getLength();
            String currentText = fb.getDocument().getText(0, length);

            if (str != null) {
                if (!isNumeric(str) && !str.equals(".") && !str.equals("-")) { //First, is it a valid character?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (str.equals(".") && currentText.contains(".")) { //Next, can we place a decimal here?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (isNumeric(str)
                                && currentText.indexOf(",") != -1
                                && offset > currentText.indexOf(",")
                                && length - currentText.indexOf(".") > decimalPrecision
                                && decimalPrecision > 0) { //Next, do we get past the decimal precision limit?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                } else if (str.equals("-") && (offset != 0 || !allowNegative)) { //Next, can we put a negative sign?
                    Toolkit.getDefaultToolkit().beep();
                    accept = false;
                }
            }
            return accept;
        }

        @Override
        public void insertString(FilterBypass fb, int offset, String str, AttributeSet as) throws BadLocationException {
            if (accept(fb, offset, str)) {
                super.insertString(fb, offset, str, as);
            }
        }

        @Override
        public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            if (accept(fb, offset, text)) {
                super.replace(fb, offset, length, text, attrs);
            }
        }

        public boolean isNumeric(String str) {
            try {
                int x = Integer.parseInt(str);
                System.out.println(x);
                return true;
            } catch (NumberFormatException nFE) {
                System.out.println("Not an Integer");
                return false;
            }
        }
    }

    public class SizeFilter extends DocumentFilter {

        private int maxCharacters;

        public SizeFilter(int maxChars) {
            maxCharacters = maxChars;
        }

        public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
                        throws BadLocationException {

            if ((fb.getDocument().getLength() + str.length()) <= maxCharacters) {
                super.insertString(fb, offs, str, a);
            } else {
                Toolkit.getDefaultToolkit().beep();
            }
        }

        public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
                        throws BadLocationException {

            if ((fb.getDocument().getLength() + str.length()
                     - length) <= maxCharacters) {
                super.replace(fb, offs, length, str, a);
            } else {
                Toolkit.getDefaultToolkit().beep();
            }
        }
    }

再一次,我知道它编译,但我没有测试它(特别是数字滤波器),但这在调试中是一个很好的练习;)

Again, I know it compiles, but I've not tested it (the numeric filter in particular), but that would be a good exercise in debugging ;)