Programming with Qt, Part 1

Qt is a set of C++ libraries and development tools commercially developed and distributed by Trolltech of Norway. Qt is available for different platforms (Win32, most flavors of Unix/Linux, as well as Mac OS X), and in several editions, including the Free Edition that's free of charge for the development of free and open source software. Trolltech's Free Edition has all of the same features of its Enterprise Edition -- at no cost!

Qt is a set of C++ libraries and development tools commercially developed and distributed by Trolltech of Norway. Qt is available for different platforms (Win32, most flavors of Unix/Linux, as well as Mac OS X), and in several editions, including the Free Edition that’s free of charge for the development of free and open source software. Trolltech’s Free Edition has all of the same features of its Enterprise Edition — at no cost!

First and foremost, Qt is a GUI-toolkit — the one used by the KDE project, in fact. However, Qt’s features have grown substantially over time, and by now (Version 3.2), its scope is very, very broad. Qt’s features can roughly be grouped into four categories: GUI widgets, including complex pre-fabricated dialogs and internationalization (I18N) support; language extensions, such as class introspection/reflection capabilities, run-time type information (RTTI), and a special intra-process communication mechanism based on the concept of signals and slots; generic utility classes, such as strings and containers, timers, regular expression (pattern matching) capabilities, and thread support, among others; and advanced “enterprise application” features, such as access libraries for XML processing, and network, file, and database access.

So, given its extent, it’s misleading to regard Qt only (or even primarily) as a GUI-toolkit. As the foregoing list suggests, Qt is more of a portable, general-purpose C++ application development framework.

Hello, World!

Using Qt, the proverbial “Hello, World” application is shown in Listing One. The program displays a friendly greeting as well as a push-button, which, when clicked, terminates the application.

Listing One: Hello, World! a la Qt

#include <qapplication.h>
#include <qvgroupbox.h>
#include <qlabel.h>
#include <qpushbutton.h>

int main( int argc, char *argv[] ) {
QApplication app( argc, argv );
QVGroupBox *dialog = new QVGroupBox(NULL);
QLabel *text = new QLabel(“Hello, World!”, dialog);
QPushButton *button = new QPushButton(“Quit”, dialog);
QObject::connect(button, SIGNAL(clicked()), &app,
dialog->move(200, 100);
return app.exec();

The program begins with a brief series of include statements. Except for the first class (QApplication), all of the other classes used in Listing One are widgets for the user interface.

For a GUI application, the QApplication class manages program-wide settings, such as the chosen color palette, fonts, and widget style, as well as parameters such as the double-click time interval. QApplication also provides the main event loop, processing events originating at the user interface. Every application that uses Qt’s GUI widgets must create exactly one instance of QApplication before creating any widgets or performing any other GUI-related activities. On the other hand, applications that use Qt exclusively for its non-GUI features (such as the container, string, and regular expression classes), do not need to use QApplication at all.

After instantiating a QApplication, the code creates three widgets for the user interface. Qt provides a variety of classes to manage the spatial arrangement of widgets, from fairly low-level layout managers, such as QHBox and QGrid, which arrange their child widgets in a horizontal row or on a tabular grid, respectively, to rather powerful organizers such as QButtonGroup and QGroupBox, which use sensible defaults to manage their children’s layout. The example code uses QVGroupBox, which arranges its contained widgets vertically, while at the same time taking into account its children’s optimal default size and resizing behavior.

You might notice that all three widgets are constructed on the heap, using new(). Furthermore, each widget is passed a pointer to its parent in its constructor, except for QVGroupBox, which is passed a NULL pointer, because it’s a top-level widget and does not have a parent within the application’s address space. In Qt’s object model, a parent widget takes ownership of the memory allocated by its children. Whenever a parent widget is destroyed, it releases the memory of all of its child widgets. Therefore, there are no corresponding calls to delete() for each of the calls to new() that instantiated the widgets. Here, the framework provides (limited) garbage collection. However, for parents to take control over the lifecycle of their child widgets like this (to adopt them), the child widgets must be constructed on the heap. If the child widgets were constructed on the stack, they would be destroyed whenever control left the current block, with catastrophic consequences for the application.

The line…

QObject::connect(button, SIGNAL(clicked()),
&app, SLOT(quit()));

… is a first glimpse of Qt’s unique intra-process communication mechanism based on signals and slots. For now, suffice it so say that whenever the “Quit” button is clicked, it emits the clicked() signal, which is connected to the application’s quit() slot by using QObject’s static member function connect(). More on signals and slots below.

Next, the code moves the window 200 pixels to the right and 100 pixels down from its default location, and makes the window visible by calling show(). Finally, the dialog box is declared as the main window of the application, and exec() is called to wait for user events.

This program can be compiled with…

% g++ -I $QTDIR/include -L $QTDIR/lib
-o hello hello.cpp -lqt

… assuming that the environment variable $QTDIR points to Qt’s installation directory, typically /usr/lib/qt3/.

Signals and Slots

The signal and slot mechanism is Qt’s way of dispatching user events to application classes. In many other GUI toolkits (notably Microsoft’s MFC and Perl’s Tk), this is done using callbacks. While callbacks are a common technique, there are several problems with the approach, not the least of which is that function pointers provide no type safety when it comes to the parameters passed when invoking the callback.

Qt’s signal and slot mechanism isn’t based around function pointers (which are necessarily only resolved at run-time), but on additional code that’s generated by a special pre-processor called the meta-object compiler, or MOC. Using MOC, the generated code will be checked for type safety by the compiler at compile time.

The example program in Listing Two demonstrates signals and slots and MOC. The application provides a window with two buttons and two displays. One of the buttons merely serves to terminate the application properly as in the previous example. The other button, however, changes the internal state of the application when clicked.

Listing Two: An example of Qt’s signals and slots

#include <qapplication.h>
#include <qobject.h>
#include <qvgroupbox.h>
#include <qpushbutton.h>
#include <qlcdnumber.h>
#include <qlabel.h>
#include <qdatetime.h>
// ————————————————————
class Counter : public QObject {

int i;

Counter(): i(0){ };

public slots:
void addOne(){
emit valueChanged(i);

void valueChanged(int);
// ————————————————————
class Clock : public QObject {

QString clocktime;

public slots:
void registerEvent(){
clocktime =
emit valueChanged(clocktime);
void valueChanged(const QString&);
// ————————————————————
int main(int argc, char *argv[]){
QApplication app(argc, argv);

Counter counter;
Clock clock;

QVGroupBox *dialog = new QVGroupBox();
QLCDNumber *lcd = new QLCDNumber(2, dialog);
QPushButton *button = new QPushButton
(“Click me…”, dialog);
QLabel *text = new QLabel(” “, dialog);
QPushButton *quit = new QPushButton(“Quit”, dialog);
QObject::connect(button, SIGNAL(clicked()),
&counter, SLOT(addOne()));
QObject::connect(button, SIGNAL(clicked()), &clock,

lcd, SLOT(display(int)));
QObject::connect(&clock, SIGNAL(valueChanged
(const QString&)),
text, SLOT(setText(const QString&)));

QObject::connect(quit, SIGNAL(clicked()), &app,

dialog->move(200, 200);

return app.exec();
#include “signals_slots.moc”

Counter and Clock are two very simple helper classes. Counter maintains the application’s state, while Clock counts the number of times the button’s been clicked and maintains a formatted string with the exact timestamp of the most recent event.

Finally, there are two display widgets that indicate the state of the application, and which therefore must be notified whenever the state changes. The LCD number on top shows the number of button presses, and the text label at the bottom displays the wall clock time of the last button press.

Each button press event must be communicated to both “business objects,” Counter and Clock, and the business objects must be able to let the GUI know when their internal state has changed. (In principle, a business object’s state could change independently of user events.) Notifications are provided through a combination of signals and slots.

Qt’s signals and slots are a publish and subscribe messaging mechanism. Any suitably instrumented object can emit signals, or can listen for signals emitted elsewhere in the application by providing slots. Signals and slots can be declared without knowledge of each other — it’s the programmer’s responsibility to connect signals to slots to achieve the intended message flow for the application.

All of Qt’s pre-defined GUI widgets offer a selection of signals and slots as part of their standard API. For instance, QPushButton can emit the clicked() signal. Listing One connected that signal to QApplication‘s quit() slot to terminate the program. Additionally, you can equip custom objects with signals and slots, allowing widgets to communicate directly with business objects and vice versa. Counter and Clock declare both signals and slots.

Classes that use signal/slot messaging must be derived from QObject, and must contain the pre-processor macro Q_ OBJECT inside the private part of the class declaration — usually done by placing it first in the class’ body. (In the next installment of this series we’ll take a closer look at the facilities this macro provides.) Beyond those two requirements, signals and slots are declared like ordinary member functions.

In fact, slots are ordinary member functions and can be called as such (circumventing the signal mechanism) when desired. Slots can be declared public, protected, or private.

Signals on the other hand are implemented through code generated by Qt’s MOC. Therefore, they must not be implemented, but only declared. To emit a signal, prepend the corresponding function call by Qt’s emit command. The three keyword lookalikes, emit, signals, and slots are other pre-processor macros that expand to nothing, but give required hints to the MOC.

The last step is to connect signals to slots, using QObject‘s static connect() member function. Any signal can be connected to any slot, provided the parameter types match (in fact, the signal may declare additional parameters that are silently ignored by the slot). In the code, notice the use of the required macros SIGNAL() and SLOT() in the calls to connect().

If a program defines its own subclasses of QObject, Qt’s MOC must be run before the actual compilation step. MOC generates the code required by the signal/slot mechanism and some other Qt language extensions. The generated code is always placed into an additional file, so that the source code you wrote isn’t changed.

The MOC can operate in two different ways: if the class declaration is found in a separate header (.h) file, the generated file is a complete C++ source (.cpp) file, commonly named moc_classname.cpp, which can be compiled separately and linked like any other source file. However, if the class declaration is found in a source (.cpp) file, the generated file (usually named classname .moc ) has to be #included into the source file after the other code, typically by placing an appropriate #include statement on the last line. That explains the last line in Listing Two.

To compile the second example program, execute:

% $QTDIR/bin/moc -o signals_slots.moc
% g++ -I $QTDIR/include/ -L $QTDIR/lib/
-o signals_slots signals_slots.cpp -lqt

More to Come

This first article in a three-part series on Qt programming developed two simple graphical applications, explored a few of Qt’s GUI widgets, and introduced Qt’s signal/slot messaging system. The next installment will take a closer look at signals and slots, show how to automate the required two-step build process by using Qt’s build-tool qmake, and expose more of Qt’s fundamental classes. Stay tuned.

Philipp K. Janert, Ph.D. is a server programmer and project manager. He maintains the beyondCode.org website, and his writings have appeared on the O’Reilly Network, IBM developer-Works, and in IEEE Software. Contact him at janert@ieee.org. You can download the code used in this column from http://www.linux-mag.com/downloads/2003-11/compile.

Comments are closed.