BUY THIS BOOK
Add to Cart

Print Book $39.95


Safari Books Online

What is this?

Add to UK Cart

Print Book £28.50

What is this?

Looking to Reprint this content?


Programming with Qt
Programming with Qt, Second Edition Writing Portable GUI applications on Unix and Win32

By Matthias Kalle Dalheimer
Price: $39.95 USD
£28.50 GBP

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Introduction
Qt is a C++ class library and GUI toolkit for Unix, Windows, and embedded systems (with the latter running on Linux). In this chapter, we will introduce GUI programming in general and Qt programming in particular. We tell you why you need a GUI toolkit and why Qt is a good choice for such a toolkit. You can check Section 1.7 to make sure you know enough about C++. This chapter also tells you where you can turn if you have any problems with Qt.
GUI toolkits are not well known in the MS Windows or Macintosh world, but they are ubiquitous on Unix. This is because the Windows GUI programming API and Macintosh programming tools already contain high-level features such as buttons, scrollbars, and functions for manipulating colors, fonts, and other visual flourishes. On Unix systems, things are different. The pre-eminent windowing system on Unix—the X Window System—is very flexible, but it does not offer the programmer much help. About the only thing you get are functions that help you draw primitive graphics like lines and rectangles, set the foreground and background color, and have user interactions and other events reported back to you. These functions are network transparent, which is a very good thing, but these limited graphical features are nevertheless difficult to program. There is nothing for creating buttons or scrollbars, let alone more complex items such as dialog boxes, toolbars, or tab pages.
Of course, nobody wants to code an entire application this way—not even the toughest of hardcore Unix programmers. This is why several toolkits have been invented to facilitate GUI programming tasks for Unix. There are many toolkits to choose from. Probably the most well-known of them is Motif, because many major Unix vendors have adopted it as their native GUI toolkit. The Common Desktop Environment (CDE), which ships with some Unix-based operating systems like Solaris and HP-UX, is based on Motif. Motif is not only a GUI toolkit, but also a specification for a certain look and feel. Motif is fairly standard, having been developed by an organization supported by many vendors: the Open Software Foundation, now called The Open Group. Why shouldn't you use it?
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why GUI Toolkits?
GUI toolkits are not well known in the MS Windows or Macintosh world, but they are ubiquitous on Unix. This is because the Windows GUI programming API and Macintosh programming tools already contain high-level features such as buttons, scrollbars, and functions for manipulating colors, fonts, and other visual flourishes. On Unix systems, things are different. The pre-eminent windowing system on Unix—the X Window System—is very flexible, but it does not offer the programmer much help. About the only thing you get are functions that help you draw primitive graphics like lines and rectangles, set the foreground and background color, and have user interactions and other events reported back to you. These functions are network transparent, which is a very good thing, but these limited graphical features are nevertheless difficult to program. There is nothing for creating buttons or scrollbars, let alone more complex items such as dialog boxes, toolbars, or tab pages.
Of course, nobody wants to code an entire application this way—not even the toughest of hardcore Unix programmers. This is why several toolkits have been invented to facilitate GUI programming tasks for Unix. There are many toolkits to choose from. Probably the most well-known of them is Motif, because many major Unix vendors have adopted it as their native GUI toolkit. The Common Desktop Environment (CDE), which ships with some Unix-based operating systems like Solaris and HP-UX, is based on Motif. Motif is not only a GUI toolkit, but also a specification for a certain look and feel. Motif is fairly standard, having been developed by an organization supported by many vendors: the Open Software Foundation, now called The Open Group. Why shouldn't you use it?
According to many programmers, using Motif is difficult, error prone, and not very much fun. It is problematic because it's based on the Xt Intrinsics, an old framework for GUI toolkits that ships with every implementation of the X Window System. The Intrinsics try to emulate object orientation in C. They succeed to a certain extent, but programming with this style is awkward and sacrifices niceties like type safety. Also, Motif programs are much longer than Qt programs that accomplish the same thing.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why Portability?
You might have asked yourself why portability is such an important goal. If you develop software for a living, probably the most important reason for having portability is to increase your possible target market. Why should you leave out millions of Unix users just because you are a Windows programmer? Can you afford not to try to sell your programs for Windows just because you prefer Unix? Toolkits make it feasible to develop a program once and recompile it to run on other platforms. Mind you, it is still not easy and there are pitfalls to watch out for. But without such a toolkit, multiplatform programming is feasible only for the largest companies.
Even if you don't develop your software for the open market, your custom software clients may require you to write programs in a portable fashion so they can sell or use them on additional platforms.
Even if you develop free software, you should remember that portable software often means better software. There might be hidden bugs in your program that a version for another platform uncovers easily. Also, following uniform standards makes it easier for other people to read and maintain your code. In addition, you can get more users if you write software that can be compiled on more than one platform, thereby making the development of free software more satisfactory.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Why Qt?
On Unix systems, Qt is the best option; it's portable, fast, and easy to use. Also, if you write free software for Unix-like operating systems such as Linux, FreeBSD, or Solaris, programming with Qt is free. In other words, you don't have to pay license fees. We will talk more about this advantage in Section 1.5.
If you are a Windows programmer, you have undoubtedly heard about MFC, the Microsoft Foundation Classes. These classes are shipped with most Windows compilers and they fulfill all the requirements that we informally listed earlier. They are complete in terms of supported user-interface elements and you can buy a lot of third-party add ons.
If MFC contains everything you need, why should you try another library—one that's completely unknown to many Windows programmers? There's one important reason: portability. When you use Qt, you can write your programs once on Windows and then recompile them to run on a lot of Unix variants, too. In addition, a lot of programmers who have used both MFC and Qt consider programming with Qt to be easier. After you have overcome the initial hurdles, you will find that programming with Qt is "the way it should be"—that is, it just feels natural. There's another reason, too—one that will appeal to most programmers: programs written with Qt tend to be very fast. This is because the programmers who wrote Qt spent a lot of time optimizing it.
Of course, other products allow portable programming for Unix and MS Windows. These products include commercial libraries like Zinc and free libraries like wxWindows. I have evaluated most of them for my projects and have always found Qt to be the best option. Of course, you should judge their merits for yourself. Try several alternatives, write sample applications, and see which toolkit is the best for you. Also, if you want to develop not only for Unix and MS Windows, but also for the Macintosh, there is no alternative but Qt.
Finally, if you are developing for embedded systems (notably, embedded systems running a version of Linux), you would have a hard time finding any GUI toolkit that comes close to Qt in terms of functionality.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Implementing Cross-Platform GUI Libraries
GUI toolkits that allow cross-platform programming can follow one of several strategies according to how the native toolkit API is used. For Windows, this native toolkit API is the Win32 API. For the purposes of this discussion, we will assume that Motif is the "native" toolkit API on Unix systems, even though no one toolkit on Unix is truly native. Motif comes closest because it is most common. On the MacOS X, the Carbon framework could be considered the native API.
Many cross-platform toolkits use API layering. This means that they provide their own API on top of the native API. There is one implementation of this toolkit for every native API that it supports. One such toolkit is wxWindows. The wxWindows methods map to Win32 API calls on Windows and to either Motif or Xt API calls on Unix (as far as I know, no version exists for the MacOS X).
The advantages of API layering are that the toolkit is relatively easy to write and that the look and feel is 100 percent compatible with the native look and feel. The disadvantages should not be ignored, however. Programs written with toolkits that use API layering are usually slower than those that use the native APIs directly because each call has to be routed through an additional layer. Native toolkits can differ significantly in their structure, which can lead to awkward control flow in the portable toolkit. In addition, those toolkits typically provide the lowest common denominator of functionality, offering only functions that are available in all supported native APIs. Finally, inheriting in widgets and specializing in them is difficult because widgets are drawn by the native toolkit and not by the relatively thin C++ wrapper.
Some other portable toolkits emulate the API of one system on all other systems. These toolkits include products such as MainWin by Mainsoft or Wind/U by Bristol Technology, which provide the Win32 API on Unix systems. It should be clear that you need no additional software for the emulated platform because the native API of this platform is used. The API emulation is only needed for other, non-native, platforms.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Acquiring Qt
The standard way to acquire a commercial license for Qt is to order it from the manufacturer, Trolltech. The company accepts credit cards and fax orders. You can find pricing information and an order form at http://www.trolltech.com/purchase/. When ordering, you can decide whether you want to get Qt delivered via normal mail on CD or if you would prefer to download it from the vendor's FTP server.
If you develop only open-source software on Unix, you don't need the commercial edition. Simply download the source code of Qt from the FTP server at ftp://ftp.trolltech.com/qt/source . You will have to compile the source code yourself, as explained in the next section. If you are unsure of which file to obtain, go to http://www.trolltech.com/products/download/ for guidance to the file you need.
If you run one of the very popular free Unix-like operating systems such as Linux or FreeBSD, your distribution probably contains a version of Qt. It might not always be the latest version, however.
Qt comes in several different editions. The difference is both what you are allowed to do with it and which features are included. The following editions are available:
Qt Free Edition
Only available on Unix/X11 and embedded systems. Contains all features of the Qt Enterprise Edition (i.e., it is the "full" package) and can only be used to develop software that is licensed under the GPL. There is no right to support with this edition.
Qt Non-Commercial Edition
Only available on MS-Windows. Contains all features of the Qt Enterprise Edition (i.e., it is the "full" package) and can only be used to develop noncommercial software (please see the accompanying license file for a more precise definition). There is no right to support with this edition.
Qt Professional Edition
Available on all supported platforms (Unix/X11, embedded systems, MS-Windows, and Macintosh). Lets you develop any type of software under any license, but leaves out some advanced modules such as the table module, the XML module, and the networking module. Includes the right to technical support.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Compiling and Installing Qt
In this section, we will describe how to build Qt on the supported systems—first Unix systems (including Qt/Embedded and the Macintosh, which behaves like a Unix system), followed by Windows systems.
Whether you buy Qt on CD or download the commercial or free version, you will end up with a tar file. Unpack this file by issuing the following command:
zcat qt-x11-3.0.1.tar.gz | tar xvf -
If you have the GNU version of tar on your system, you can use this command:
tar xvzf qt-x11-3.0.1.tar.gz
Qt will be unpacked in a directory called qt-x11-commercial-3.0.1 (or a similar directory for the embedded and MacOS X platforms). Of course, you can save yourself work if you unpack the archive where you want to have it, which might be /usr/local. You should now read the INSTALL file in this directory to see if there are any special directions for your system.
Since Qt/Embedded is basically a Qt for Unix (notably Linux) that brings its own window system, there are hardly any differences in building Qt/Embedded and Qt for Unix/X11; you can just follow these instructions for building Qt/Embedded. But note that you either need framebuffer support compiled into your Linux kernel or the qvfb tool mentioned later.
Qt is pretty big, but you will rarely need everything in it. You could build a leaner version of Qt. During the build, the file $QTDIR/include/qconfig.h is included. You can add several preprocessor macros that exclude certain parts of Qt from compilation. See the sample files qconfig-large.h, qconfig-medium.h, qconfig-minimal.h, or qconfig-small.h for examples, or the file $QTDIR/doc/html/features.html in the reference documentation for a complete list.
In most cases, building the Qt library is straightforward. The process has two steps. The first step configures Qt for your system and the second builds the Qt library and examples.
A note about version numbers: when you read this book, there could already be a newer version of Qt. In this case, the version numbers in the filenames will change, but the general process will probably not.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
C++ as Used by Qt
If you are unsure whether your C++ knowledge is extensive enough for programming with Qt, this section can help. It gives you a short rundown of the part of C++ that Qt and Qt programs use, so you will know if you lack some C++ skills.
If you want to read about some of the language features mentioned here, we recommend C++: The Core Language by Gregory Satir and Doug Brown (O'Reilly). This book concentrates on the most important parts of the language and covers almost everything mentioned here.
Objects and Classes
Of course, Qt uses classes—it is a class library. You should know what member functions are and how to call them. Also, you need to know how to write your own classes and how to derive a new class from an existing one. You do not need to be an experienced designer of class hierarchies, though. We will provide enough information here on building up your hierarchies for GUI programming.
Access Methods
Qt uses a lot of access methods, which are methods that get and set values of private class variables. Set methods usually start with set... (e.g., setText()), while get methods have no prefix (not even get—, e.g., text()). This is fairly basic stuff; there's no sophistication involved here.
Polymorphism and Virtual Functions
Qt uses virtual functions to notify your objects about low-level events (such as mouseclicks or repaint events), so you should be comfortable with these functions. Unlike other toolkits and class libraries, Qt uses the innovative signal/slot mechanism rather than virtual functions as the central means of communication between objects. This feature is specific to Qt, so it is covered later in this book.
Inheritance
Of course, Qt uses inheritance, but for the most part, it relies on single inheritance. Multiple inheritance is rarely used—in fact, it is used so rarely that you might never get to see it. If you have never understood what this "virtual inheritance" means, rest assured: Qt does not use it at all.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Getting Help
You may run into problems that you cannot solve with the Qt reference documentation or this book. There are several places where you can ask for help:
  • If you have a professional or enterprise license for Qt, you are entitled to technical support via email. You will receive the email address with your copy of Qt. Usually, you will get answers very quickly, but if your questions are difficult, please be patient.
  • You can subscribe to the Qt Interest mailing list, through which a thousand Qt users exchange ideas and help one another. The developers of Qt monitor this mailing list as well, and sometimes jump in if nobody else knows an answer. Please keep in mind that the other developers on this list are not there just to help you. Most of them are very supportive, but nobody is required to answer your questions. To subscribe, send an email message with the text subscribe insert your email address here in the subject to qt-interest-request@trolltech.com. After you have subscribed, you can post a message to the list by sending email to qt-interest@trolltech.com.
  • The K Desktop Environment (KDE) (see http://www.kde.org) mailing lists are populated with some very experienced Qt developers, too, so you can ask for help there if you are writing a KDE application. Remember that most KDE programmers do their work voluntarily in their spare time, so please be polite and do not demand quick answers. Please see the web site http://www.kde.org/mailinglists.html for information about which lists exist and how to subscribe to them.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: First Steps in Qt Programming
The time has come to start getting our hands dirty with some real code. Of course, our first program will be the traditional "Hello, world" exercise. We'll then gradually build from there to create a small, but complete, paint program. The topics in this chapter are important building blocks for almost every Qt programming task, so make sure you understand them.
This program, which creates a little window with "Hello, world" in it, is very simple. It contains code (see Example 2-1) that you will see often in Qt programs.
Example 2-1. helloworld.cpp: Hello, world in Qt
#include <qapplication.h>
#include <qlabel.h>

int main( int argc, char* argv[] )
{
  QApplication myapp( argc, argv );

  QLabel* mylabel = new QLabel( "Hello, world", 0 );
  mylabel->resize( 120, 30 );

  myapp.setMainWidget( mylabel );
  mylabel->show();
  return myapp.exec();
}
Let's go through this code line by line. The first two lines include Qt header files. For most cases, a one-to-one relationship exists between Qt classes and Qt header files. The header file names are almost always the same as the class names, with all letters in lowercase and the conventional .h appended to each name. In some rare cases, several classes are grouped together in one header file. For example, you can find both the class declarations of QListView and QListViewItem in qlistview.h. When in doubt, check the documentation. Shortly, we'll cover how the Qt reference documentation is organized. In this example, qapplication.h is for the class QApplication and qlabel.h is for QLabel.
Line 6 is the next crucial line. Here, an object of class QApplication is created. Every Qt application must have exactly one object of class QApplication. This object is responsible for all event handling and it holds everything together. It also provides some useful methods (member functions), which we'll talk about later.
You probably have noticed that the command-line parameters that our application receives from the runtime library are passed to the constructor of the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Hello, world!
This program, which creates a little window with "Hello, world" in it, is very simple. It contains code (see Example 2-1) that you will see often in Qt programs.
Example 2-1. helloworld.cpp: Hello, world in Qt
#include <qapplication.h>
#include <qlabel.h>

int main( int argc, char* argv[] )
{
  QApplication myapp( argc, argv );

  QLabel* mylabel = new QLabel( "Hello, world", 0 );
  mylabel->resize( 120, 30 );

  myapp.setMainWidget( mylabel );
  mylabel->show();
  return myapp.exec();
}
Let's go through this code line by line. The first two lines include Qt header files. For most cases, a one-to-one relationship exists between Qt classes and Qt header files. The header file names are almost always the same as the class names, with all letters in lowercase and the conventional .h appended to each name. In some rare cases, several classes are grouped together in one header file. For example, you can find both the class declarations of QListView and QListViewItem in qlistview.h. When in doubt, check the documentation. Shortly, we'll cover how the Qt reference documentation is organized. In this example, qapplication.h is for the class QApplication and qlabel.h is for QLabel.
Line 6 is the next crucial line. Here, an object of class QApplication is created. Every Qt application must have exactly one object of class QApplication. This object is responsible for all event handling and it holds everything together. It also provides some useful methods (member functions), which we'll talk about later.
You probably have noticed that the command-line parameters that our application receives from the runtime library are passed to the constructor of the QApplication object. This step is done because QApplication accepts some special command-line arguments, which it handles and removes later from the command-line variables. Your application never sees these special command-line arguments. Among them are -style, which tells Qt which widget style to use by default; and -nograb, which tells Qt never to grab the mouse or the keyboard to facilitate debugging. If your application interprets its own command-line parameters, make sure to interpret them after having passed the command line to
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using the Qt Reference Documentation
Qt comes with documentation in HTML format, and it is simply excellent. That's the main reason why you won't find a reference section in this book. It's not very difficult to find your way around the documentation, but it pays to take some time to get acquainted with it. It will help you work faster.
There are two ways to use the reference documentation. First, you can use any web browser (as described later in this section), since the documentation is shipped in plain HTML. Second, you can also use the program Qt Assistant, which is shipped together with Qt. The assistant has the advantage that it indexes the whole documentation, which makes it easier to search for something if you have absolutely no idea where to look for it in the documentation. On the other hand, you are probably already comfortable with your web browser, and its features for bookmarks are likely to be stronger than those of Qt Assistant as well. Qt Assistant is started by issuing assistant (assuming that you have installed Qt correctly as described in the previous chapter). It is fairly self-explanatory, so we will concentrate on guiding you through the Qt documentation using a web browser here (Qt Assistant has a browser-like view, so you can even follow what we describe here with Qt Assistant, if you like).
To read the documentation, fire up your web browser. Since Qt does not use any special HTML tricks, and because it doesn't rely on Java or JavaScript, you can use any web browser. Konqueror, Netscape Navigator, Internet Explorer, Lynx, or Opera are fine, for example. If you have several browsers to choose from, use the one you already know best. If you still don't know which browser to use, pick one with good bookmark support.
Point your browser to the file index.html in the doc/html directory of your Qt installation. You will see something similar to the page in Figure 2-2.
Figure 2-2: The start page of the Qt reference documentation
To get an idea of how Qt's class tree is organized, choose the item Annotated Classes
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding an Exit Button
In this section, we will extend our little "Hello, world" program with a push button. A push button is a common interface element on every platform: you just click on it, and something happens. In Qt, push buttons are represented by the class QPushButton—a subclass of QButton, which itself is a subclass of QWidget, the base class for all Qt UI elements. Besides showing how to create a push button, which is not very different from the label we created two sections ago, this example gives you a first impression of how to react to user interaction in Qt. The first task will be very simple: when the user presses the button (which will ingeniously be labeled "Quit"), the whole program will terminate. Before we start explaining, you should look at the program in Example 2-2 and its output in Figure 2-4.
Example 2-2. pushbutton.cpp: Adding a push button to Hello, world
#include <qapplication.h>
#include <qlabel.h>
#include <qpushbutton.h>

int main( int argc, char* argv[] )
{
  QApplication myapp( argc, argv );

  QWidget* mywidget = new QWidget;
  mywidget->setGeometry( 400, 300, 120, 90 );

  QLabel* mylabel = new QLabel( "Hello world", mywidget );
  mylabel->setGeometry( 10, 10, 80, 30 );

  QPushButton* myquitbutton = new QPushButton( "Quit", mywidget );
  myquitbutton->setGeometry( 10, 50, 100, 30 );
  QObject::connect( myquitbutton, SIGNAL(clicked()), 
                    &myapp, SLOT(quit()) );

  myapp.setMainWidget( mywidget );
  mywidget->show();
  return myapp.exec();
}
Figure 2-4: Output of the button program
We had to change some things here to accommodate more than one widget. Since we now have two, we have to create an additional widget to bring together the label and the push button. This additional widget is represented by the variable mywidget. It is an object of the class QWidget, meaning that it has no special widget properties, but knows about all the general things that widgets can do, such as resizing and moving.
In the constructors for the QLabel object and the QPushButton object, we pass the address of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction to Signals and Slots
As explained in the last section, signals and slots are the most important topic in Qt programming. To help you understand how signals and slots work, we'll look at how other GUI toolkits link events, such as when the user presses a button to program code. We will see why there are disadvantages with these methods, which will give us a better understanding of why the developers of Qt chose the signal-and-slot mechanism. If you already know about other GUI toolkits or libraries such as MFC or Motif, you can skip to Section 2.4.2.
The underlying window system reports user interactions with so-called "events." These events are usually very primitive and just say "the user pressed the left mouse button while the mouse was at position 100, 200" or "the user pressed the k key." Of course, it would be possible to determine from the mouse position which widget the mouse was over when the user pressed the button and then react accordingly, but this would be a very boring, cumbersome, and error-prone task that we rightfully expect the toolkit to take over for us.
Accordingly, the toolkit determines which widget the mouse was over—in other words, which widget should be informed about the mouseclick. The next question is how and where the programmer should put the code to be executed in reaction to the mouseclick. GUI toolkits differ most fundamentally in how they answer this question.
Motif uses callbacks. Callbacks are C functions that must accept certain arguments and are "registered" with a widget. Every Motif widget knows about certain callback types for which callback functions may be registered. For example, the push button knows about callbacks when the mouse is pressed, released, and clicked. The disadvantage of this method is the missing type safety. If you register a function with an incorrect signature (and it accepts the wrong types of parameters), your application will probably crash. The compiler cannot guard you from this outcome.
There is no connection between the widget and the callback, which is just any other standalone function that happens to be registered as a callback function. In addition, when it comes to object-oriented programming with C++, callbacks are even more awkward. Because of the implicitly passed
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Event Handling and Simple Drawings with QPainter
Now that you know how to create widgets and how to use signals and slots, we can target our initial goal: writing a small paint program. In this section, we will learn how to use the class QPainter, which encapsulates Qt's drawing routines. At the end of this section, we will have a small program for scribbling your own drawings in a predefined color. You will also learn a bit about handling low-level events.
QPainter is one of Qt's strengths. It is a class that bundles many highly optimizing routines for drawing graphical objects such as lines, circles, and Bézier curves. In addition, it supports different coordinate systems and geometrical transformations including rotating, scaling, and shearing. Furthermore, it supports the use of these operations with widgets, pixmaps, metafiles, and printers alike.
Since we want to use the mouse for drawing, we have to learn how to react to mouse events that are not related to special widgets such as push buttons. We will have to be notified that the mouse has been pressed, released, or dragged in the plain void. You might suspect that we are in for more signals and slots now, but that is not the case. The developers of Qt have chosen another mechanism to report low-level events: virtual methods.
As you may recall from the last chapter, toolkits like wxWindows rely exclusively on virtual methods for event reporting. We have already explained why this is a bad idea: you always have to derive your own classes just to get notified about a button click.
This criticism applies only to widgets that work out of the box, though; a push button does everything itself. When the user clicks on it, it changes its appearance accordingly and notifies the application program via a signal. When it is obscured by some other window and later unhidden again, it automatically redisplays itself without help from the rest of the application or the window system.
This situation is different in roll-your-own widgets. You have to derive your widget from QWidget anyway to handle the redisplay, and if you already have derived your own class, it does not matter much if you override some virtual methods for low-level events such as mouse movements and key presses.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Learning More About Qt
By now, you know the basics of programming with Qt, but we have only begun. In this chapter, we continue to work on our painting program by adding features such as menus and file access.
In this section, you will learn how to work with menus. Qt menus mainly consist of two classes: QMenuBar and QPopupMenu. Both are derived from a common base class, QMenuData. Thus, working with menu bars and pop-up menus is very similar. A menu bar serves as a container for its menus, which are just objects of the type QPopupMenu. These menus can have other submenus, which are also objects of type QPopupMenu. In addition, you can also use pop-up menus (also called contextual menus) directly, for example, when the user presses the right mouse button.
For our painting program, we will define three menus: a menu that will contain only a entry, a menu that will allow the user to choose the painting color, and a menu that will contain only an entry. We'll add more items to these menus later.
Again, we first present you with the complete code and tell you how it works afterwards. The code is in Example 3-1; its output is in Figure 3-1. The new or changed lines have been set in boldface for your convenience.
Example 3-1. qtscribble2.cpp: Adding a menu bar to our painting application
#include <qapplication.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qwidget.h>

enum MenuIDs{
    COLOR_MENU_ID_BLACK,
    COLOR_MENU_ID_RED,
    COLOR_MENU_ID_BLUE,
    COLOR_MENU_ID_GREEN,
    COLOR_MENU_ID_YELLOW };

/**
  * A class that lets the user draw with the mouse. The
  * window knows how to redraw itself.
  */
class ScribbleWindow : public QWidget
{
  Q_OBJECT  // necessary because ScribbleWindow contains slots
  
public:
  ScribbleWindow();
  ~ScribbleWindow();

protected:
  virtual void mousePressEvent( QMouseEvent* );
  virtual void mouseMoveEvent( QMouseEvent* );
  virtual void paintEvent( QPaintEvent* );
  virtual void resizeEvent( QResizeEvent* );

Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding Menus
In this section, you will learn how to work with menus. Qt menus mainly consist of two classes: QMenuBar and QPopupMenu. Both are derived from a common base class, QMenuData. Thus, working with menu bars and pop-up menus is very similar. A menu bar serves as a container for its menus, which are just objects of the type QPopupMenu. These menus can have other submenus, which are also objects of type QPopupMenu. In addition, you can also use pop-up menus (also called contextual menus) directly, for example, when the user presses the right mouse button.
For our painting program, we will define three menus: a menu that will contain only a entry, a menu that will allow the user to choose the painting color, and a menu that will contain only an entry. We'll add more items to these menus later.
Again, we first present you with the complete code and tell you how it works afterwards. The code is in Example 3-1; its output is in Figure 3-1. The new or changed lines have been set in boldface for your convenience.
Example 3-1. qtscribble2.cpp: Adding a menu bar to our painting application
#include <qapplication.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qwidget.h>

enum MenuIDs{
    COLOR_MENU_ID_BLACK,
    COLOR_MENU_ID_RED,
    COLOR_MENU_ID_BLUE,
    COLOR_MENU_ID_GREEN,
    COLOR_MENU_ID_YELLOW };

/**
  * A class that lets the user draw with the mouse. The
  * window knows how to redraw itself.
  */
class ScribbleWindow : public QWidget
{
  Q_OBJECT  // necessary because ScribbleWindow contains slots
  
public:
  ScribbleWindow();
  ~ScribbleWindow();

protected:
  virtual void mousePressEvent( QMouseEvent* );
  virtual void mouseMoveEvent( QMouseEvent* );
  virtual void paintEvent( QPaintEvent* );
  virtual void resizeEvent( QResizeEvent* );

private slots:
  void slotAbout();
  void slotAboutQt();
  void slotColorMenu( int );

private:
  QPoint _last;
  QColor _currentcolor;
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding a Scrolled View
The drawing area in a painting application should not be constrained by the size of the application window. With horizontal and vertical scrollbars, you can let the user draw into a virtual area that is much bigger than the application window. Qt provides the class QScrollView, which allows you to add scrollbars to your programs easily. Just specify the widget you want to make scrollable, and QScrollView does the rest for you. You can specify whether the scrollbars should always be visible, off (in this case, you will have to provide another means of scrolling, such as with the keyboard), or automatic. Automatic scrollbars are only visible when the visible area of the scrolled widget is smaller than the widget itself; in other words, when there is something to scroll.
The code in Example 3-2, whose output can be found in Figure 3-2, shows how to add a QScrollView to our painting application.
Example 3-2. qtscribble3.cpp: A painting application with scrollbars
#include <qapplication.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qscrollview.h>
#include <qwidget.h>

enum MenuIDs{
    COLOR_MENU_ID_BLACK,
    COLOR_MENU_ID_RED,
    COLOR_MENU_ID_BLUE,
    COLOR_MENU_ID_GREEN,
    COLOR_MENU_ID_YELLOW };

/**
  * A class that lets the user draw scribbles with the mouse. The
  * window knows how to redraw itself.
  */
class ScribbleArea : public QWidget
{
  Q_OBJECT  // necessary because ScribbleArea contains a slot
  
public:
  ScribbleArea();  
  ~ScribbleArea();

public slots:
  void setColor( QColor );

protected:
  virtual void mousePressEvent( QMouseEvent* );
  virtual void mouseMoveEvent( QMouseEvent* );
  virtual void paintEvent( QPaintEvent* );
  virtual void resizeEvent( QResizeEvent* );

private:
  QPoint _last;
  QColor _currentcolor;

  QPixmap _buffer;
};

class ScribbleWindow : public QWidget
{
  Q_OBJECT

public:
  ScribbleWindow();
  ~ScribbleWindow();

private slots:
  void slotAbout();
  void slotAboutQt();
  void slotColorMenu( int );

Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Adding a Context Menu
Our next improvement to the paint application is a pop-up menu. A pop-up menu is a menu that pops up in response to a mouseclick, usually with the right button, rather than being pulled down from a menu bar. Of course, many things could be added to such a pop-up menu, but for now we will content ourselves with one menu entry: Clear, which wipes the entire drawing off the screen.
Like the other menus in a menu bar, pop-up menus are objects of type QPopupMenu. The only difference is that you do not attach them to a QMenuBar object by calling insertItem(). Instead, you create a QPopupMenu and show it later by calling either exec() or popup(). The former performs a blocking popup of a pop-up menu, which means that the method call returns only when the menu was popped down again either by selecting a menu entry or by clicking somewhere else. In contrast, popup() pops up the menu and the method call returns immediately.
No matter how you pop up the menu, you can always be notified by connecting to the normal signals activated( int ) and highlighted( int ). In addition, when you pop up the menu in a blocked way via exec(), this method returns the item number of the item selected. It returns -1 if no item has been selected because the menu has been popped down by clicking somewhere else.
As you might already have guessed from the last two paragraphs, you need not be concerned with popping down pop-up menus. Qt does this for you automatically.
Normally, you will want to pop up a menu in response to a mouseclick at the position where the mouse was clicked. QPopupMenu makes it very easy to do this because both exec() and popup() accept a QPoint as the first parameter that indicates the global coordinates of the pop-up menu (where 0,0 is the top left corner of the screen).
Since you can get the global mouse coordinates by simply calling QCursor::pos(), all you have to do in response to a mouseclick is call:
mypopupmenu->exec( QCursor::pos() );
If you would rather have your pop-up menu aligned with a different widget, you must first translate that widget's coordinates to global coordinates with the method
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
File I/O
In this section, we will explore some issues related to input and output of data in files. Our goal will be to load and save the drawings in a file that can be specified using a file selection dialog.
Several issues are involved here. The first is the file selection dialog. Qt provides the class QFileDialog, so you don't have to roll your own. Actually, the static methods getOpenFileName() and getSaveFileName() will do almost all of the work.
The next item is the file format. There are several options to explore here. The first is simply saving the data from the off-screen buffer. This is easy because it is an object of type QPixmap and QPixmap provides a method save() for storing the data in one of several supported file formats.
Another option is to record all drawings in a QPicture object instead of a QPixmap. We mentioned this option before as a way to manage off-screen data. Like QPixmap, QPicture has a save() method. QPicture uses a file format of its own, which is portable across all platforms that Qt supports, but cannot be read by any non-Qt application. The difference between the QPixmap variant and the QPicture variant is mainly one of storing pixel data or storing vector-based graphics data. The goals of your application will determine what the best option is. For our application, it does not really matter, but since we use a large virtual drawing area, a vector-based file format would probably be more space efficient. On the other hand, saving with QPixmap requires using a well-known file format so you can check the results of the save operation with tools such as MS Paint on Windows or pixmap on Unix systems. Therefore, we have decided to use QPixmap for the save operations here.
Now that we have made our basic decisions we can start to implement the load and save operations. Example 3-4 contains the program.
Example 3-4. qtscribble5.cpp: Load and save operations
#include <qapplication.h>
#include <qfiledialog.h>
#include <qmenubar.h>
#include <qmessagebox.h>
#include <qpainter.h>
#include <qpixmap.h>
#include <qpopupmenu.h>
#include <qscrollview.h>
#include <qwidget.h>
#include <qcursor.h>

enum MenuIDs{
    COLOR_MENU_ID_BLACK,
    COLOR_MENU_ID_RED,
    COLOR_MENU_ID_BLUE,
    COLOR_MENU_ID_GREEN,
    COLOR_MENU_ID_YELLOW };

/**
  * A class that lets the user draw with the mouse. The
  * window knows how to redraw itself.
  */
class ScribbleArea : public QWidget
{
  Q_OBJECT  // necessary because ScribbleArea contains slots
  
public:
  ScribbleArea();
  ~ScribbleArea();

public slots:
  void setColor( QColor );
  
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: A Guided Tour Through the Simple Widgets
Qt is a rich library and as a beginner, you could easily find yourself reinventing the wheel when a Qt class that meets your needs already exists. This is why we present widgets that are already available with their most useful methods in this chapter and in Chapter 5. We also provide guidelines that specify when to use a certain widget.
This widget tour has two parts. This chapter presents so-called simple widgets, such as push buttons and labels. The next chapter contains the predefined dialog boxes that Qt provides for common tasks such as opening files, as well as the building blocks for defining your own dialogs. Some widgets with a more specific task, such as those used for displaying database data, are described in other chapters to stay with their underlying classes.
For most of the widgets, we show screenshots depicting them in both Windows and Motif styles because these styles are used most frequently. In other styles like the SGI style, the widgets may look somewhat different. To ensure that you can find them easily in the reference, most screenshots are taken directly from the Qt reference documentation, with the kind permission of Trolltech AS.
For your convenience, Table 4-1 contains all widgets that ship with Version 3 of Qt. They are listed alphabetically, each with a short description and a reference to the section of this book where they are explained further.
Table 4-1: The widget classes in Qt 3
WidgetDescriptionSection
QButton
A common base class for button-like widgets
See Section 4.3.
QButtonGroup
Organizes QButton widgets in a group
See Section 4.8.2.
QCanvasView
A widget that displays a canvas with items on it
See Section 9.7 in Chapter 9.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
General Widget Parameters
All widgets in this chapter serve as building blocks for your application; most of them are commonly found in dialogs. Of course, these widgets all have the general properties of Qt widgets. You can, for example, set their fonts and colors. See the reference documentation for QWidget for these methods. The method setEnabled(), which accepts a bool parameter for influencing whether a widget is available for user interaction, is very useful. Enabling and disabling widgets, depending on the situation, is very important for creating good user interfaces. Disabled widgets are displayed "grayed out." All too often, you see programs in which you can choose some settings, and then you are told "Sorry, this choice is not possible." Worse, you may be offered choices that have absolutely no effect. These choices waste the user's time. Remember this when you design your application—your users will thank you for it.
Other settings that apply to all widgets are the font, which is set with setFont(), and the palette for drawing, which is set with setPalette() (you can learn more about palettes in Section 9.3.3 in Chapter 9).
Note the uniformity of the constructors of widgets in Qt. Most widgets have a constructor with three parameters: a QWidget* that specifies the parent, a name (see Chapter 21 to find out how this is used), and widget flags, which only apply to top-level widgets and are rarely needed even for them. You can create a top-level widget without passing any parameters to the constructor because all three parameters usually default to 0. You can create any other widget simply by passing the parent.
Some widgets also provide additional overloaded constructors. These constructors provide parameters for setting additional initial properties. For example, you can pass the label for the push button as a parameter to the constructor of the class QPushButton. Any additional parameters usually come before the standard ones.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Widget Styles
Qt uses GUI emulation, so it can use widgets with a Windows style in Unix and widgets with a Motif style in Windows—or you can use a different style altogether. You could even mix widgets with different styles in your application, but doing so is not recommended.
There are several ways to set the style of widgets:
  • You can set the style for an individual widget by calling setStyle() on the widget object and passing a pointer to an object of a class that inherits from QStyle. The two most frequently used subclasses are QWindowsStyle and QMotifStyle, but there is also QCDEStyle (which emulates the look and feel of the Common Desktop Environment in a way that's similar to QMotifStyle), QMotifPlusStyle (a Motif-like style with better bevelling and highlighting buttons when the mouse rolls over them), QSGIStyle (a Motif-like style that looks like systems running the Unix-variant Irix from Silicon Graphics), and QPlatinumStyle (which emulates the look of the standard style of the Java Swing toolkit). Qt/Embedded also includes QCompactStyle, which is similar to QWindowsStyle, but which occupies less screen real estate (useful on embedded devices with limited screen resolutions). Finally, in the Qt version of MacOS X, QAquaStyle emulates the default Aqua style used in MacOS X. If you build Qt on Windows XP, you can configure it to use an additional QXPStyle.
    As noted before, setting a certain style for an individual widget is not recommended.
  • You can set the default for all widgets by calling the static method QApplication::setStyle(). You should call this method before any widget is created or repaint all the widgets afterwards. This repainting can be done with the following code:
     
    // set the default 
    QApplication::setStyle( new QWindowsStyle ); // or any other style you like
    // get a list of all top-level widgets of the application 
    QWidgetList* widgetlist = QApplication::topLevelWidgets(); 
    
    // create an iterator over the list 
    QWidgetListIt widgetlist_it( *widgetlist ); 
    
    // do the following for each top-level widget 
    while( widgetlist_it.current() )
    { 
      // take one widget from the list 
      QWidget* widget = widgetlist_it.current(); 
    
      // advance the iterator to the next element 
      ++widgetlist_it; 
    
      // apply the new style to this widget 
      widget->setStyle( newstyle ); 
    
      // get a list of all descendants of this widget that are widgets 
      // themselves 
      QObjectList* objectlist = widget->queryList( "QWidget", 0, 0, true ); 
    
      // create an iterator over this list 
      QObjectListIt objectlist_it( *objectlist ); 
    
      // apply the new style to all descendant widgets 
      while ( objectlist_it.current() )
      {
        ++objectlist_it; // advance iterator to next element,
                         // the current one is already changed
        QWidget *child = (QWidget *)( objectlist_it.current() ); 
        child->setStyle( newstyle ); 
      } 
      delete objectlist; 
    } 
    
    delete widgetlist;
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Buttons
Buttons are probably the most common GUI element. You can group them according to how they are used: push buttons yield some kind of action such as closing a dialog box or invoking a program-specific function. On the other hand, radio buttons and checkboxes, which are collectively known as option buttons, are used to select options rather than to invoke actions. With push buttons, this is usually not possible because something happens as soon as they are clicked. There is also a visual difference: push buttons appear "pressed in" only while clicked, while option buttons change appearance when clicked and keep that appearance.
Push buttons are represented by the class QPushButton (see Figure 4-1) in Qt. These buttons yield some kind of action, such as closing a dialog box or invoking a program-specific function. They can be labeled with either text or pixmaps, using the method setText() or setPixmap(). A text string can also be passed in the constructor. You usually connect a slot to the signal clicked(), which is emitted when the mouse is pressed and released again over the button.
The signals pressed() and released() are also available, but you should be careful with them, since you are probably on your way to designing a hard-to-use GUI if you use them. There is also a signal called toggled(), which is only emitted in a special mode of a QPushButton object (we will discuss this signal later).
Figure 4-1: The push button in Windows and Motif style (both look the same)
A push button that resides in a dialog can become the default push button. This push button is "clicked" when the user presses the Enter key. Of course, there can only be one default button in a dialog box. Make a push button the default button by calling setDefault() on it. A related method is setAutoDefault(), which makes a button an autodefault button. Unlike the default button, there can be more than one autodefault button. An autodefault button becomes the new default button when it gets the keyboard focus, and it loses this property when the keyboard focus moves to a different widget.
Additional content appearing in this section has