Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QValidator for hex input

Tags:

c++

qt

qlineedit

I have a Qt widget which should only accept a hex string as input. It is very simple to restrict the input characters to [0-9A-Fa-f], but I would like to have it display with a delimiter between "bytes" so for example if the delimiter is a space, and the user types 0011223344 I would like the line edit to display 00 11 22 33 44 Now if the user presses the backspace key 3 times, then I want it to display 00 11 22 3.

I almost have what i want, so far there is only one subtle bug involving using the delete key to remove a delimiter. Does anyone have a better way to implement this validator? Here's my code so far:

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

For now this code is functional enough, but I'd love to have it work 100% as expected. Obviously the ideal would be the just separate the display of the hex string from the actual characters stored in the QLineEdit's internal buffer but I have no idea where to start with that and I imagine is a non-trivial undertaking.

In essence, I would like to have a Validator which conforms to this regex: "[0-9A-Fa-f]( [0-9A-Fa-f])*" but I don't want the user to ever have to type a space as delimiter. Likewise, when editing what they types, the spaces should be managed implicitly.

like image 936
Evan Teran Avatar asked May 03 '10 18:05

Evan Teran


2 Answers

Evan, try this:

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

The inputMask takes care of the spacing, and the "h" stands for a optional hex character (the "H" for a non-optional). Only drawback: You have to know the maximum input length in advance. My example above allows only for four bytes.

Best regards, Robin

like image 147
Robin Avatar answered Sep 29 '22 06:09

Robin


I will propose three approaches :

You can reimplement the QLineEdit::keyPressEvent() to handle backslash differently when the character just left to the QLineEdit's cursor is a space. Using this approach, you can also automatically add spaces when a new character is typed.

Another approach is to create a new slot, connected to the QLineEdit::textChanged() signal. This signal is emitted when the text is changed. In this slot, you can handle the creation and deletion of spaces accordingly to your needs.

Finally, you can create a new class, derived from QLineEdit that reimplements the QLineEdit::paintEvent() method. With this approach, you can display space between your hex words that are not stored in the QLineEdit buffer.

like image 28
Lohrun Avatar answered Sep 29 '22 07:09

Lohrun