Как в Java я могу создать поле, которое может принимать только цифры и одну точку?

Я смотрю по всей сети, и все, что я пробовал, не сработало....

Я обнаружил, что могу использовать 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);
        }
    });

но это не работает... Он принимает только цифры. Я хочу, чтобы он также принимал точки. И мне также нужно, чтобы он не начинался с точки и не заканчивался точкой.

что я делаю не так?


person Alex Kapustian    schedule 11.05.2015    source источник
comment
but it doesn't work... пожалуйста, определите...   -  person Thomas    schedule 11.05.2015
comment
извините, я отредактировал свой вопрос   -  person Alex Kapustian    schedule 11.05.2015
comment
I also need it to not to start with a dot and not to end with a dot. - выражение для этого будет ^\d+(\.\d+)?$, т. е. как минимум одна цифра, за которой может следовать точка, и как минимум еще одна цифра.   -  person Thomas    schedule 11.05.2015


Ответы (2)


Недавно у меня была похожая проблема. Проблема была не в регулярном выражении, а в моем непонимании того, как работает фильтр. Мое предположение, как и ваше, заключалось в том, что String text, переданный методу replace, представляет собой всю строку, хотя на самом деле это только набираемый символ. Аналогичное обсуждение здесь.

Хотя все кунг-фу регулярного выражения @Bohemian могут быть тем, что вы ищете с точки зрения соответствующего регулярного выражения (я не знаете, это не моя сильная сторона), проблема (с предположением) может быть устранена путем получения всего текста документа, а затем попытаться сопоставить это, т.е.

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();
            }
        });
    }
}
person Paul Samsotha    schedule 11.05.2015
comment
ты прав. как я могу сделать это с точкой в ​​конце? - person Alex Kapustian; 11.05.2015
comment
Вы пробовали это с регулярным выражением, которое вы используете в настоящее время? Похоже, это должно работать, как только вы сделаете исправление, о котором я упоминал. - person Paul Samsotha; 11.05.2015
comment
да, fb.getDocument().getText(0, fb.getDocument().getLength()); пуст... fb.getDocument().getLength() возвращает 0 - person Alex Kapustian; 11.05.2015
comment
Тогда вы делаете что-то не так. См. обновление будет полной программой - person Paul Samsotha; 11.05.2015
comment
Да, поэтому я забыл тот факт, что новая строка/символ еще не вставлена ​​в документ. Вот почему необходимо конкатенировать перед сопоставлением :-) - person Paul Samsotha; 11.05.2015

Это, вероятно, самый простой код, который работает:

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

Если есть точка, за ней должны следовать несколько цифр. Если вы хотите разрешить и точку, и никаких цифр, измените + на *:

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

Обратите внимание, что с String#matches() начальные/конечные ^/$ не нужны, поскольку они подразумеваются, потому что вся строка должна сопоставляться для matches(), чтобы вернуть true.

Разрешить отсутствие начальных цифр также становится сложнее, потому что регулярное выражение (\d+)?(\.\d*) соответствует пустой строке, поэтому вам нужно чередование:

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

или негативный взгляд вперед:

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

Маленькая голова взгляда утверждает, что следующая позиция после начала не является концом (т.е. ввод не пустой).

person Bohemian♦    schedule 11.05.2015