QValidator для шестнадцатеричного ввода - PullRequest
7 голосов
/ 03 мая 2010

У меня есть виджет Qt, который должен принимать в качестве входных данных только шестнадцатеричную строку. Очень просто ограничить вводимые символы [0-9A-Fa-f], но я бы хотел, чтобы он отображался с разделителем между байтами, например, если разделитель является пробелом, а пользователь вводит 0011223344, я хотел бы Редактирование строки для отображения 00 11 22 33 44 Теперь, если пользователь нажимает клавишу возврата 3 раза, я хочу, чтобы она отображала 00 11 22 3.

У меня почти есть то, что я хочу, пока есть только одна тонкая ошибка, связанная с использованием ключа удаления для удаления разделителя. У кого-нибудь есть лучший способ реализовать этот валидатор? Вот мой код:

class HexStringValidator : public QValidator {
public:
    HexStringValidator(QObject * parent) : QValidator(parent) {}

public:
    virtual void fixup(QString &input) const {
        QString temp;
        int index = 0;

            // every 2 digits insert a space if they didn't explicitly type one 
        Q_FOREACH(QChar ch, input) {
            if(std::isxdigit(ch.toAscii())) {

                if(index != 0 && (index & 1) == 0) {
                    temp += ' ';
                }

                temp += ch.toUpper();
                ++index;
            }
        }

        input = temp;
    }

    virtual State validate(QString &input, int &pos) const {
        if(!input.isEmpty()) {
            // TODO: can we detect if the char which was JUST deleted
            // (if any was deleted) was a space? and special case this?
            // as to not have the bug in this case?

            const int char_pos  = pos - input.left(pos).count(' ');
            int chars           = 0;
            fixup(input);

            pos = 0;

            while(chars != char_pos) {
                if(input[pos] != ' ') {
                    ++chars;
                }
                ++pos;
            }

            // favor the right side of a space
            if(input[pos] == ' ') {
                ++pos;
            }
        }
        return QValidator::Acceptable;
    }
};

Пока этот код достаточно функционален, но я бы хотел, чтобы он работал на 100%, как и ожидалось. Очевидно, что идеальным было бы просто отделить отображение шестнадцатеричной строки от фактических символов, хранящихся во внутреннем буфере QLineEdit, но я понятия не имею, с чего начать, и я думаю, что это нетривиальное начинание.

По сути, я хотел бы иметь Validator, который соответствует этому регулярному выражению: "[0-9A-Fa-f]( [0-9A-Fa-f])*", но я не хочу, чтобы пользователь когда-либо вводил пробел в качестве разделителя. Аналогично, при редактировании того, что они печатают, пробелы должны управляться неявно.

Ответы [ 3 ]

6 голосов
/ 04 мая 2010

Эван, попробуйте это:

QLineEdit * edt = new QLineEdit( this );  
edt->setInputMask( "Hh hh hh hh" );

InputMask заботится о расстоянии, а «h» обозначает необязательный шестнадцатеричный символ («H» - необязательный) Единственный недостаток: вы должны знать максимальную длину ввода заранее. Мой пример выше допускает только четыре байта.

С уважением, Robin

1 голос
/ 12 сентября 2018

Робин решение хорошо и работает. Но я думаю, что вы можете сделать лучше всего!
Используйте это для ввода маски:

ui->lineEdit->setInputMask("HH-HH-HH-HH");

и в пользовательском интерфейсе R-щелкните на lineEdit -> Go to Slots ... -> textChanged. В слот функции напишите этот код:

int c = ui->lineEdit->cursorPosition();
ui->lineEdit->setText(arg1.toUpper());
ui->lineEdit->setCursorPosition(c); // to not jump cursor's position

Теперь у вас есть lineEdit с шестнадцатеричным вводом, в верхнем регистре, с разделителями тире.

хорошее время кода:)

1 голос
/ 04 мая 2010

Я предложу три подхода:

Вы можете переопределить QLineEdit::keyPressEvent(), чтобы по-разному обрабатывать обратную косую черту, когда символ, оставленный курсором QLineEdit, является пробелом. Используя этот подход, вы также можете автоматически добавлять пробелы при вводе нового символа.

Другой подход заключается в создании нового слота, подключенного к сигналу QLineEdit::textChanged(). Этот сигнал испускается при изменении текста. В этом слоте вы можете обрабатывать создание и удаление пробелов в соответствии с вашими потребностями.

Наконец, вы можете создать новый класс, производный от QLineEdit, который переопределяет метод QLineEdit::paintEvent(). При таком подходе вы можете отобразить пробел между шестнадцатеричными словами, которые не хранятся в буфере QLineEdit.

...