In some cases, we find that a Qt widget requires more customization than is possible by setting its properties in Qt Designer or by calling its functions. A simple and direct solution is to subclass the relevant widget class and adapt it to suit our needs.
Figure 5.1. The HexSpinBox widget
In this section, we will develop a hexadecimal spin box to show how this works. QSpinBox only supports decimal integers, but by subclassing it's quite easy to make it accept and display hexadecimal values.
#ifndef HEXSPINBOX_H #define HEXSPINBOX_H #include class HexSpinBox : public QSpinBox { public: HexSpinBox(QWidget *parent, const char *name = 0); protected: QString mapValueToText(int value); int mapTextToValue(bool *ok); }; #endif
The HexSpinBox inherits most of its functionality from QSpinBox. It provides a typical constructor and reimplements two virtual functions from QSpinBox. Since the class doesn't define its own signals and slots, it doesn't need the Q_ OBJECT macro.
#include #include "hexspinbox.h" HexSpinBox::HexSpinBox(QWidget *parent, const char *name) : QSpinBox(parent, name) { QRegExp regExp("[0-9A-Fa-f]+"); setValidator(new QRegExpValidator(regExp, this)); setRange(0, 255); }
The user can modify a spin box's current value either by clicking its up and down arrows or by typing a value into the spin box's line editor. In the latter case, we want to restrict the user's input to legitimate hexadecimal numbers. To achieve this, we use a QRegExpValidator that accepts one or more characters from the ranges '0' to '9', 'A' to 'F', and 'a' to 'f'. We also set the default range to be 0 to 255 (0x00 to 0xFF), which is more appropriate for a hexadecimal spin box than QSpinBox's default of 0 to 99.
QString HexSpinBox::mapValueToText(int value) { return QString::number(value, 16).upper(); }
The mapValueToText() function converts an integer value to a string. QSpinBox calls it to update the editor part of the spin box when the user presses the spin box's up or down arrows. We use the static function QString::number() with a second argument of 16 to convert the value to lower-case hexadecimal, and call QString::upper() on the result to make it upper-case.
int HexSpinBox::mapTextToValue(bool *ok) { return text().toInt(ok, 16); }
The mapTextToValue() function performs the reverse conversion, from a string to an integer value. It is called by QSpinBox when the user types a value into the editor part of the spin box and presses Enter. We use the QString::toInt() function to attempt to convert the current text (returned by QSpinBox::text()) to an integer value, again using base 16.
If the conversion is successful, toInt() sets *ok to true; otherwise, it sets it to false. This behavior happens to be exactly what QSpinBox expects.
We have now finished the hexadecimal spin box. Customizing other Qt widgets follows the same pattern: Pick a suitable Qt widget, subclass it, and reimplement some virtual functions to change its behavior. This technique is common in Qt programming; in fact, we have already used it in Chapter 4 when we subclassed QTable and reimplemented createEditor() and endEdit().
Part I: Basic Qt
Getting Started
Creating Dialogs
Creating Main Windows
Implementing Application Functionality
Creating Custom Widgets
Part II: Intermediate Qt
Layout Management
Event Processing
2D and 3D Graphics
Drag and Drop
Input/Output
Container Classes
Databases
Networking
XML
Internationalization
Providing Online Help
Multithreading
Platform-Specific Features