An improved HexSpinBox

We get a change request for our hexadecimal spin box. The user would like to use the keyboard to change its value, and actually he wants to use the plus and minus key to increase/decrease the value by one unit and the tab and shift-tab (AKA backtab) to increase/decrease by 16 (0x10) units.

The first requirement is a normal one, and would be resolved implementing in our class a redefinition for the keyPressEvent() virtual function, as showed below.

The second requirement is a bit wierd. Usually we want tab and backtab be reserved for shifting among the various write-accessible widget in our window, so it is not often a good idea to change its default meaning. But in this case our user is quite sure he wants this behaviour, and it is not a big issue to make him happy: we just have to reimplement the event() virtual function in our class in this way:

bool HexSpinBox::event(QEvent *event)
{
if(event->type() == QEvent::KeyPress) // 1.
{
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent *>(event); // 2.
if(keyEvent)
{
switch(keyEvent->key()) // 3.
{
case Qt::Key_Tab:
setValue(value() + 0x10);
return true;
case Qt::Key_Backtab:
setValue(value() - 0x10);
return true;
}
}
}
return QSpinBox::event(event); // 4.
}

1. the event() function is called for each event is fired when the widget is in focus. Currently we are interested in changing its behaviour for a specific KeyPress event, so we check that the current managed event is such an event.
2. QKeyEvent is the event used to describe the KeyEvents. So it is actually a bit paranoid to dynamic_cast the event to this type, since there should be no way a KeyPress is associated to something different to a QKeyEvent. But the universe is big and an extra-check here is not that expensive, so I went for it.
3. we check the key the user has pressed, and increase the current value for our spin box accordingly to the requirements.
4. finally we pass the control to the superclass implementation for this function.

For the "normal" keys (not the tab-associated ones, I mean) the job is even easier. No need of downcasting, since the keyPressEvent() function already knows the right type of associated events:

void HexSpinBox::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_Plus:
setValue(value() + 1);
break;
case Qt::Key_Minus:
setValue(value() - 1);
break;
default:
QSpinBox::keyPressEvent(event);
}
}

So it is just a matter of checking the key actually pressed, changing the current value accordingly, and finally calling the superclass implementation for the function.

I suggest you reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield for more details on the matter.

No comments:

Post a Comment