Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Mastering Qt  5
Mastering Qt  5

Mastering Qt 5: Create stunning cross-platform applications using C++ with Qt Widgets and QML with Qt Quick , Second Edition

Arrow left icon
Profile Icon Guillaume Lazar Profile Icon Robin Penea
Arrow right icon
$27.98 $39.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.1 (8 Ratings)
eBook Aug 2018 534 pages 2nd Edition
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Guillaume Lazar Profile Icon Robin Penea
Arrow right icon
$27.98 $39.99
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.1 (8 Ratings)
eBook Aug 2018 534 pages 2nd Edition
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Mastering Qt 5

Get Your Qt Feet Wet

If you know C++ but have never touched Qt, or if you have already made some intermediate Qt applications, this chapter will ensure that your Qt foundations are solid before studying advanced concepts in the following chapters.

We will teach you how to create a simple todo application using Qt Creator. This application will display a list of tasks that you can create/update/delete. We will cover the Qt Creator and Qt Designer interfaces, an introduction to the signal/slot mechanism, the creation of a custom widget with custom signals/slots, and its integration into your application.

You will implement a todo app using new C++14 semantics: lambdas, auto variables, and for loops. Each of these concepts will be explained in depth and will be used throughout this book.

By the end of this chapter, you will be able to create a desktop application with a flexible UI using Qt widgets and new C++ semantics.

In this chapter, we will cover the following topics:

  • Qt project basic structure
  • MainWindow structure
  • Qt Designer interface
  • Signals and slots
  • Custom QWidget
  • C++14 lambda, auto, and for each

Qt project basic structure

First, start Qt Creator.

By default, Qt Creator is configured to use and generate lowercase filenames (such as mainwindow.cpp). As this book is using the Pascal case (that is, MainWindow.cpp), you should disable it. Uncheck the Tools | Options... | C++ | File Naming | Lower case file names option.

You can now create a new Qt project via File | New File or Project | Application | Qt Widgets Application | Choose.

The wizard will then guide you through four steps:

  1. Location: Choose a project name and location
  2. Kits: Target platforms that your project aims at (Desktop, Android, and so on)
  3. Details: Input base class information and a name for the generated class
  4. Summary: Allows you to configure your new project as a subproject and automatically add it to a version-control system

Even if all the default values can be kept, please at least set a useful project name, such as "todo" or "TodoApp." We won't blame you if you want to call it "Untitled" or "Hello world."

Once done, Qt Creator will generate several files, which you can see in the Projects hierarchy view:

The .pro file is Qt's configuration project file. As Qt adds specific file formats and C++ keywords, an intermediate build step is performed, parsing all the files to generate the final files. This process is done by qmake, an executable from the Qt SDK. It will also generate the final Makefiles for your project.

A basic .pro file generally contains:

  • Qt modules used (such as core, gui)
  • A target name (such as todo, todo.exe)
  • A project template (such as app, lib)
  • Sources, headers, and forms

There are some great features that come with Qt and C++14. This book will showcase them in all its projects. For the GCC and CLANG compilers, you must add CONFIG += c++14 to the .pro file to enable C++14 on a Qt project, as shown in the following code:

QT       += core gui 
CONFIG   += c++14 
 
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 
 
TARGET = todo 
TEMPLATE = app 
 
SOURCES += main.cpp \ 
           MainWindow.cpp 
 
HEADERS  += MainWindow.h \ 
 
FORMS    += MainWindow.ui \ 

The MainWindow.h and MainWindow.cpp files are the header/source for the MainWindow class. These files contain the default GUI generated by the wizard.

The MainWindow.ui file is your UI design file written in XML format. It can be edited more easily with Qt Designer. This tool is a What You See Is What You Get (WYSIWYG) editor that helps you to add and adjust your graphical components, known as widgets.

Here is the main.cpp file, with its well-known function:

#include "MainWindow.h" 
#include <QApplication> 
 
int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 
    MainWindow w; 
    w.show(); 
 
    return a.exec(); 
} 

Usually, the main.cpp file contains the program entry point. It will, by default, perform three actions:

  • Instantiate QApplication
  • Instantiate and show your main window
  • Execute the blocking main event loop

This is the bottom-left toolbar for Qt Creator:

Use it to build and start your todo application in debug mode:

  1. Check that the project is in Debug build mode
  2. Use the hammer button to build your project
  3. Start debugging using the green Play button with the little blue bug

You will discover a wonderful and beautifully empty window. We will rectify this after explaining how MainWindow is constructed:

  • Press Ctrl + B (for Windows/Linux) or Command + B (for Mac) to build your project
  • Press F5 (for Windows/Linux) or Command + R (for Mac) to run your application in debug mode

MainWindow structure

This generated class is a perfect yet simple example of Qt framework usage; we will dissect it together. As mentioned previously, the MainWindow.ui file describes your UI design and the MainWindow.h/MainWindow.cpp files define the C++ object where you can manipulate the UI with code.

It's important to take a look at the MainWindow.h header file. Our MainWindow object inherits from Qt's QMainWindow class:

#include <QMainWindow> 
 
namespace Ui { 
class MainWindow; 
} 
 
class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 
 
public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 
private: 
    Ui::MainWindow *ui; 
}; 

As our class inherits from the QMainWindow class, we will have to add the corresponding #include at the top of the header file. The second part is the forward declaration of Ui::MainWindow, as we only declare a pointer.

Q_OBJECT can look a little strange to a non-Qt developer. This macro allows the class to define its own signals/slots through Qt's meta-object system. These features will be covered later in this chapter in the section Signals and slots.

This class defines a public constructor and destructor. The latter is pretty common but the constructor takes a parent parameter. This parameter is a QWidget pointer that is null by default.

QWidget is a UI component. It can be a label, a textbox, a button, and so on. If you define a parent-child relationship between your window, layout, and other UI widgets, the memory management of your application will be easier. Indeed, in this case, deleting the parent is enough because its destructor will take care of also deleting its child recursively.

Our MainWindow class extends QMainWindow from the Qt framework. We have a ui member variable in the private fields. Its type is a pointer of Ui::MainWindow, which is defined in the ui_MainWindow.h file generated by Qt. It's the C++ transcription of the MainWindow.ui UI design file. The ui member variable will allow you to interact with your C++ UI components (QLabel, QPushButton, and so on), as shown in the following figure:


If your class only uses pointers or references for a class type, you can avoid including the header by using forward declaration. That will drastically reduce compilation time and avoid circular dependencies.

Now that the header part is done, we can talk about the MainWindow.cpp source file.

In the following code snippet, the first include is our class header. The second one is required by the generated Ui::MainWindow class. This include is required as we only use a forward declaration in the header:

#include "MainWindow.h" 
#include "ui_MainWindow.h" 
 
MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

In many cases, Qt generates good code using the initializer list. The parent argument is used to call the QMainWindow superclass constructor. Our ui private member variable is also initialized.

Now that ui is initialized, we must call the setupUi function to initialize all the widgets used by the MainWindow.ui design file:

As the pointer is initialized in the constructor, it must be cleaned in the destructor:

MainWindow::~MainWindow() 
{ 
    delete ui; 
} 

Qt Designer interface

Qt Designer is a major tool for developing Qt applications. This WYSIWYG editor will help you to easily design your GUI. If you switch between Edit mode and Design mode for the MainWindow.ui file, you will see the real XML content and the designer:

The designer displays several parts:

  • Form Editor (1): A visual representation of the form (empty for now)
  • Widget Box (2): Contains all the major widgets that can be used with your form
  • Object Inspector (3): Displays your form as a hierarchical tree
  • Property Editor (4): Enumerates the properties of the selected widget
  • Action Editor/Signal & Slots Editor (5): Handles toolbar actions and connections between your objects

It's time to embellish this empty window! Let's drag and drop a Label widget from the Display Widgets section on the form. You can change the name and the text properties directly from the Properties editor.

As we are making a todo application, we suggest these properties:

  • objectName: statusLabel
  • text: Status: 0 todo / 0 done

This label will later display the count of todo tasks and the count of tasks already done. Save, build, and start your application. You should now see your new label in the window.

You can now add a push button with those properties:

  • objectName: addTaskButton
  • text: Add task

You should get a result close to the following:


You can edit the text property of a widget directly on your form by double-clicking on it!

The design of the MainWindow.ui file is ready, we can now study the signals and slots.

Signals and slots

The Qt framework offers a flexible message-exchange mechanism that is composed of three concepts:

  • signal is a message sent by an object
  • slot is a function that will be called when this signal is triggered
  • The connect function specifies which signal is linked to which slot

Qt already provides signals and slots for its classes, which you can use in your application. For example, QPushButton has signal clicked(), which will be triggered when the user clicks on the button. Another example: the QApplication class has a slot quit() function, which can be called when you want to terminate your application.

Here is why you will love Qt signals and slots:

  • A slot remains an ordinary function, so you can call it yourself
  • A single signal can be linked to different slots
  • A single slot can be called by different linked signals
  • A connection can be made between a signal and a slot from different objects, and even between objects living inside different threads

Keep in mind that to be able to connect a signal to a slot, their methods' signatures must match. The count, order, and type of arguments must be identical. Note that signals and slots never return values.

This is the syntax of a Qt connection:

connect(sender, &Sender::signalName,  
    receiver, &Receiver::slotName); 

The first test that we can do to use this wonderful mechanism is to connect an existing signal with an existing slot. We will add this connect call to the MainWindow constructor:

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
    connect(ui->addTaskButton, &QPushButton::clicked, 
    QApplication::instance(), &QApplication::quit); 
} 

Let's analyze how a connection is done:

  • sender: Object that will send the signal. In our example, the QPushButton named addTaskButton is added from the UI designer.
  • &Sender::signalName: Pointer to the member signal function. Here, we want do something when the clicked signal is triggered.
  • receiver: Object that will receive and handle the signal. In our case, it is the QApplication object created in main.cpp.
  • &Receiver::slotName: Pointer to one of the receiver's member slot functions. In this example, we use the built-in quit() slot from QApplication, which will exit the application.

You can now compile and run this short example. You will terminate the application if you click on addTaskButton of your MainWindow.


You can connect a signal to another signal. The second signal will be emitted when the first one is triggered.

Now that you know how to connect a signal to an existing slot, let's see how to declare and implement a custom addTask() slot in our MainWindow class. This slot will be called when the user clicks on ui->addTaskButton.

The following is the updated MainWindow.h:

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 
 
public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 
 
public slots: 
    void addTask(); 
 
private: 
    Ui::MainWindow *ui; 
}; 

Qt uses a specific slots keyword to identify slots. Since a slot is a function, you can always adjust the visibility (public, protected, or private) depending on your needs.

We will now add this slot implementation in the MainWindow.cpp file:

void MainWindow::addTask() 
{ 
    qDebug() << "User clicked on the button!"; 
} 

Qt provides an efficient way of displaying the debug information with the QDebug class. An easy way to obtain a QDebug object is to call the qDebug() function. Then you can use the << stream operator to send your debug information.

Update the top of the file like the following:

#include <QDebug> 
 
MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
    connect(ui->addTaskButton, &QPushButton::clicked, 
    this, &MainWindow::addTask); 
} 

Since we now use qDebug() in our slot, we must include <QDebug>. The updated connect now calls our custom slot instead of quitting the application.

Build and run the application. If you click on the button, you will see your debug message inside the Application Output Qt Creator tab.

Custom QWidget

We now have to create the Task class that will hold our data (task name and completed status). This class will have its form file separated from MainWindow. Qt Creator provides an automatic tool to generate a base class and the associated form.

Click on File | New File or Project | Qt | Qt Designer Form Class. There are several form templates; you will recognize Main Window, which Qt Creator created for us when we started the todo app project. Select Widget and name the class Task, then click on Next. Here is a summary of what Qt Creator will do:

  1. Create a Task.h file and a Task.cpp file
  2. Create the associated Task.ui and do the plumbing to connect to Task.h
  3. Add these three freshly-created files to todo.pro so they can be compiled

Finish and voilà, the Task class is ready to be filled. We will jump into Task.ui first. Start by dragging and dropping checkbox (objectName = checkbox) and Push Button (objectName = removeButton):

This layout looks great, let's ship it to the customers! Unless you have a pixel-perfect eye, your items are not very well aligned. You need to indicate how your widgets should be laid out and how they should react when the window geometry changes (for example, when the user resizes the window). For this, Qt has several default layout classes:

  • Vertical Layout: Widgets are vertically stacked
  • Horizontal Layout: Widgets are horizontally stacked
  • Grid Layout: Widgets are arranged in a grid that can be subdivided into smaller cells
  • Form Layout: Widgets are arranged like a web form, a label, and an input

A basic layout will try to constrain all its widgets to occupy equal surfaces. It will either change the widgets' shape or add extra margins, depending on each widget's constraints. Check Box will not be stretched but Push Button will.

In our Task object, we want this to be horizontally-stacked. In the Form Editor tab, right-click on the window and select Lay out | Lay out Horizontally. Each time you add a new widget in this layout, it will be arranged horizontally.

Now add a Push Button (objectName = editButton) just after the checkbox object.

The Form Editor window offers a realistic preview of how your UI will render. If you stretch the window now, you can observe how each widget will react to this event. When resizing horizontally, you can note that the push buttons are stretched. It looks bad. We need something to "hint" to the layout that these buttons should not be stretched. Enter the Spacer widget. Take Horizontal Spacer in the widget box and drop it after the checkbox object:

A spacer is a special widget that tries to push (horizontally or vertically) adjacent widgets to force them to take up as little space as possible. The editButton and removeButton objects will take up only the space of their text and will be pushed to the edge of the window when resized.

You can add sub layouts of any type in a form (vertical, horizontal, grid, form) and create a complex-looking application with a combination of widgets, spacers, and layouts. These tools are targeted at designing a good-looking desktop application that can react properly to different window geometries.

The Designer part is finished, so we can switch to the Task source code. Since we created a Qt Designer Form class, Task is closely linked to its UI. We will use this as a leverage to store our model in a single place. When we create a Task object, it has to have a name:

#ifndef TASK_H 
#define TASK_H 
 
#include <QWidget> 
#include <QString> 
 
namespace Ui { 
class Task; 
} 
 
class Task : public QWidget 
{ 
    Q_OBJECT 
 
public: 
    explicit Task(const QString& name, QWidget *parent = 0); 
    ~Task(); 
 
    void setName(const QString& name); 
    QString name() const; 
    bool isCompleted() const; 
     
private: 
    Ui::Task *ui; 
}; 
 
#endif // TASK_H 

The constructor specifies a name and, as you can see, there are no private fields storing any state of the object. All of this will be done in the form part. We also added some getters and setters that will interact with the form. It's better to have a model completely separated from the UI, but our example is simple enough to merge them. Moreover, the Task implementation details are hidden from the outside world and can still be refactored later on. Here is the content of the Task.cpp file:

#include "Task.h" 
#include "ui_Task.h" 
 
Task::Task(const QString& name, QWidget *parent) : 
        QWidget(parent), 
        ui(new Ui::Task) 
{ 
    ui->setupUi(this); 
    setName(name); 
} 
 
Task::~Task() 
{ 
    delete ui; 
} 
 
void Task::setName(const QString& name) 
{ 
    ui->checkbox->setText(name); 
} 
 
QString Task::name() const 
{ 
    return ui->checkbox->text(); 
} 
 
bool Task::isCompleted() const 
{ 
   return ui->checkbox->isChecked(); 
} 

The implementation is straightforward; we store the information in ui->checkbox and both the name() and the isCompleted() getters take their data from ui->checkbox.

Adding a task

We will now rearrange the layout of MainWindow to be able to display our todo tasks. At this moment, there is no widget where we can display our tasks. Open the MainWindow.ui file. We will use Qt designer to create the UI:

  1. Drag and drop Horizontal layout inside the central widget and rename it toolbarLayout
  2. Right-click on the central widget and select Lay out vertically
  3. Drag and drop the label, spacer, and button inside toolbarLayout
  4. Drag and drop Vertical layout under toolbarLayout (a blue helper line will be displayed) and rename it tasksLayout
  5. Add a vertical spacer under tasksLayout (again, check the blue helper line):

Voilà! Your MainWindow form is finished. Later in the chapter you will learn how to dynamically create and add some Task widgets to the empty tasksLayout.

To sum up, we have:

  • A vertical layout for centralWidget that contains the toolbarLayout item and the tasksLayout item.
  • A vertical spacer pushing these layouts to the top, forcing them to take up the smallest possible space.
  • Gotten rid of menuBar, mainToolBar, and statusBar. Qt Creator created them automatically, we simply don't need them for our purposes. You can guess their uses from their names.

Don't forget to rename the MainWindow title to Todo by selecting MainWindow in the Object Inspector window and editing the Qwidget | windowTitle property. Your app deserves to be named properly.


Press Shift + F4 in Designer mode to switch between the form editor and the source.

Now that the MainWindow UI is ready to welcome tasks, let's switch to the code part. The application has to keep track of new tasks. Add the following in the MainWindow.h file:

#include <QVector> 
 
#include "Task.h" 
 
class MainWindow : public QMainWindow 
{ 
    // MAINWINDOW_H 
 
public slots: 
    void addTask(); 
 
private: 
    Ui::MainWindow *ui; 
    QVector<Task*> mTasks; 
};

The QVector is the Qt container class providing a dynamic array, which is an equivalent of std::vector. Generally speaking, the rule says that STL containers are more customizable, but they may miss some features compared to Qt containers. If you use C++11 smart pointers, you should favor std containers, but we will get into that later.

In the Qt documentation of QVector, you may stumble upon the following statement: For most purposes, QList is the right class to use. There is a debate about this in the Qt community:

  • Do you often need to insert objects larger than a pointer at the beginning or in the middle of your array? Use a QList class.
  • Need contiguous memory allocation? Less CPU and memory overhead? Use a QVector class.

The already-added addTask() slot will now be called each time we want to add a new Task object to the mTasks function.

Let's fill our QVector tasks each time addTaskButton is clicked. First, we connect the clicked() signal in the MainWindow.cpp file:

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow), 
    mTasks() 
{ 
    ui->setupUi(this); 
    connect(ui->addTaskButton, &QPushButton::clicked,  
    this, &MainWindow::addTask); 
}; 
As a best practice, try to always initialize member variables in the initializer list and respect the order of variable declarations. Your code will run faster and you will avoid unnecessary variable copies. For more information, take a look at the standard C++ documentation at https://isocpp.org/wiki/faq/ctors#init-lists.

The body of the addTask() function should look like this:

void MainWindow::addTask() 
{ 
        qDebug() << "Adding new task"; 
        Task* task = new Task("Untitled task"); 
        mTasks.append(task); 
        ui->tasksLayout->addWidget(task); 
} 

We created a new task and added it to our mTask vector. Because the Task object is a QWidget, we also added it directly to tasksLayout. An important thing to note here is that we never managed our new task's memory. Where is the delete task instruction? This is a key feature of the Qt Framework we started to mention earlier in the chapter; the QObject class parenting automatically handles object destruction.

In the preceding code snippet, the ui->tasksLayout->addWidget(task) call has an interesting side-effect: the ownership of the task is transferred to the layout's widget. The QObject* parent defined in the Task constructor is now centralWidget of the MainWindow. The Task destructor will be called when MainWindow releases its own memory by recursively iterating through its children and calling their destructor.

This feature has interesting consequences. First, if you use the QObject parenting model in your application, you will have much less memory to manage. Second, it can collide with some new C++11 semantics, specifically the smart pointers. We will get into the details about this in later chapters.

Using a QDialog

We deserve something better than an untitled task. The user needs to define its name when created. The easiest path would be to display a dialog where the user can input the task name. Fortunately, Qt offers us a very configurable dialog that fits perfectly in addTask():

#include <QInputDialog> 
... 
void MainWindow::addTask() 
{ 
    bool ok; 
    QString name = QInputDialog::getText(this,  
        tr("Add task"), 
        tr("Task name"), 
        QLineEdit::Normal, 
        tr("Untitled task"),               &ok); 
    if (ok && !name.isEmpty()) { 
        qDebug() << "Adding new task"; 
        Task* task = new Task(name); 
        mTasks.append(task); 
        ui->tasksLayout->addWidget(task); 
    } 
}

The QinputDialog::getText function is a static blocking function that displays the dialog. When the user validates/cancels the dialog, the code continues. If we run the application and try to add a new task, we will see this:

The QInputDialog::getText signature looks like this:

QString QinputDialog::getText( 
  QWidget* parent,  
      const QString& title,  
      const QString& label,  
      QLineEdit::EchoMode mode = QLineEdit::Normal,  
      const QString& text = QString(),  
      bool* ok = 0, ...)

Let's break it down:

  • parent: This is the parent widget (MainWindow) to which QinputDialog is attached. This is another instance of the QObject class's parenting model.
  • title: This is the title displayed in the window title. In our example, we use tr("Add task"), which is how Qt handles i18n in your code. Later, we will see how to provide multiple translations for a given string.
  • label: This is the label displayed right above the input text field.
  • mode: This is how the input field is rendered (password mode will hide the text).
  • ok: This is a pointer to a variable that is set to true if the user presses OK and false if the user presses Cancel.
  • QString: The returned QString is what the user has typed.

There are a few more optional parameters we can safely ignore for our example.

Distributing code responsibility

Great, the user can now specify a task name when created. What if they make an error when typing the name? The next logical step is to be able to rename the task after we create it. We'll take a slightly different approach. We want our Task to be as autonomous as possible. If we attach it to another component (rather than MainWindow), this renaming feature has to keep working. Thus, this responsibility has to be given to the Task class:

// In Task.h 
public slots: 
    void rename(); 
 
// In Task.cpp 
#include <QInputDialog> 
 
Task::Task(const QString& name, QWidget *parent) : 
       QWidget(parent), 
       ui(new Ui::Task) 
{ 
   ui->setupUi(this); 
   setName(name); 
   connect(ui->editButton, &QPushButton::clicked, this, &Task::rename); 
} 
... 
void Task::rename() 
{ 
    bool ok; 
    QString value = QInputDialog::getText(this, tr("Edit task"), 
                                          tr("Task name"), 
                                          QLineEdit::Normal, 
                                          this->name(), &ok); 
    if (ok && !value.isEmpty()) { 
        setName(value); 
    } 
} 

We add a public rename() slot to connect it to a signal. The body of rename() reuses what we had previously covered with QInputDialog. The only difference is the QInputDialog default value, which is the current task name. When setName(value) is called, the UI is instantly refreshed with the new value; there's nothing to synchronize or update, the Qt main loop will do its job.

The nice thing is that Task::rename() is completely autonomous. Nothing has been modified in MainWindow, so we have effectively zero coupling between our Task and the parent QWidget.

Emitting a custom signal using lambdas

The remove task is straightforward to implement, but we'll study some new concepts along the way. The Task has to notify its owner and parent (the MainWindow) that the removeTaskButton QPushButton has been clicked. We'll implement this by defining a custom removed signal in the Task.h files:

class Task : public QWidget 
{ 
    ... 
public slots: 
    void rename(); 
signals: 
    void removed(Task* task); 
   ... 
}; 

Like we did for the slots, we have to add the Qt keyword signals in our header. Since signal is used only to notify another class, the public keyword is not needed (it even raises a compilation error). signal is simply a notification sent to the receiver (the connected slot); it implies that there is no function body for the removed(Task* task) function.

We added the task parameter to allow the receiver to know which task asked to be removed. The next step is to emit the removed signal upon the removeButton click. This is done in the Task.cpp file:

Task::Task(const QString& name, QWidget *parent) : 
        QWidget(parent), 
        ui(new Ui::Task) 
{ 
    ui->setupUi(this); 
    ... 
    connect(ui->removeButton, &QPushButton::clicked, [this] { 
        emit removed(this); 
    }); 
} 

This code excerpt shows a very interesting feature of C++11: lambdas. In our example, lambda is the following part:

[this] { 
        emit removed(this); 
    }); 

Here, we connected the clicked signal to an anonymous inline function, a lambda. Qt allows signal-relaying by connecting a signal to another signal if their signatures match. It's not the case here: the clicked signal has no parameter and the removed signal needs a Task*. A lambda avoids the declaration of a verbose slot in Task. Qt 5 accepts a lambda instead of a slot in a connect, and both syntaxes can be used.

Our lambda executes a single line of code: emit removed(this). Emit is a Qt macro that will trigger the connected slot with what we passed as the parameter. As we said earlier, removed(Task* this) has no function body, its purpose is to notify the registered slot of an event.

Lambdas are a great addition to C++. They offer a very practical way of defining short functions in your code. Technically, a lambda is the construction of a closure capable of capturing variables in its scope. The full syntax goes like this:

[ capture-list ] ( params ) -> ret { body }

Let's study each part of this statement:

  • capture-list: Defines what variables will be visible inside the lambda scope.
  • params: This is the function parameter's type list that can be passed to the lambda scope. There are no parameters in our case. We might have written [this] () { ... }, but C++11 lets us skip the parentheses altogether.
  • ret: This is the return type of the lambda function. Just like params, this parameter can be omitted if the return type is void.
  • body: This is obviously your code body where you have access to your capture-list and params, and which must return a variable with a ret type.

In our example, we captured the this pointer to be able to:

  • Have a reference on the removed() function, which is part of the Task class. If we did not capture this, the compiler would have shouted error: 'this' was not captured for this lambda function emit removed(this);.
  • Pass this to the removed signal: the caller needs to know which task triggered removed.

capture-list relies on standard C++ semantics: capture variables by copy or by reference. Let's say that we wanted to print a log of the name constructor parameter and we capture it by reference in our lambda:

connect(ui->removeButton, &QPushButton::clicked, [this, &name] { 
        qDebug() << "Trying to remove" << name; 
        this->emit removed(this); 
    }); 

This code will compile fine. Unfortunately, the runtime will crash with a dazzling segmentation fault when we try to remove a Task. What happened? As we said, our lambda is an anonymous function that will be executed when the clicked() signal has been emitted. We captured the name reference, but this reference may be invalid once we get out of the Task constructor (more precisely, from the caller scope). The qDebug() function will then try to display an unreachable code and crash.

You really need to be careful with what you capture and the context in which your lambda will be executed. In this example, the segmentation fault can be amended by capturing name by copy:

connect(ui->removeButton, &QPushButton::clicked, [this, name] { 
        qDebug() << "Trying to remove" << name; 
        this->emit removed(this); 
    }); 
  • You can capture by copy or reference all variables that are reachable in the function where you define your lambda with the = and & syntax.
  • The this variable is a special case of the capture list. You cannot capture it by the [&this] reference and the compiler will warn you if you are in this situation: [=, this]. Don't do this. Kittens will die.

Our lambda is passed directly as a parameter to the connect function. In other words, the lambda is a variable. This has many consequences: we can call it, assign it, and return it. To illustrate a "fully formed" lambda, we can define one that returns a formatted version of the task name. The sole purpose of this snippet is to investigate the lambda function's machinery. Don't include the following code in your todo app, your colleagues might call you a "functional zealot":

connect(ui->removeButton, &QPushButton::clicked, [this, name] { 
    qDebug() << "Trying to remove" << 
        [] (const QString& taskName) -> QString { 
            return "-------- " + taskName.toUpper(); 
    }(name); 
    emit removed(this); 
}); 

Here we did a tricky thing. We called qDebug(). Inside this call, we defined a lambda that is immediately executed. Let's analyze it:

  • []: We performed no capture. lambda does not depend on the enclosing function.
  • (const Qstring& taskName): When this lambda is called, it will expect a QString to work on.
  • -> QString: The returned value of the lambda will be a QString.
  • return "------- " + taskName.toUpper(): The body of our lambda. We return a concatenation of a string and the uppercase version of the taskName parameter. As you can see, string-manipulation becomes a lot easier with Qt.
  • (name): Here comes the catch. Now that the lambda function is defined, we can call it by passing the name parameter. In a single expression, we define it then call it. The qDebug() function will simply print the result.

The real benefit of this lambda will emerge if we are able to assign it to a variable and call it multiple times. C++ is statically typed, so we must provide the type of our lambda variable. In the language specification, a lambda type cannot be explicitly defined. We will soon see how we can do it with C++11. For now, let's finish our remove feature.

The task now emits the removed() signal. This signal has to be consumed by MainWindow:

// in MainWindow.h 
public slots: 
    void addTask(); 
    void removeTask(Task* task); 
 
// In MainWindow.cpp 
void MainWindow::addTask() 
{ 
    ... 
    if (ok && !name.isEmpty()) { 
        qDebug() << "Adding new task"; 
        Task* task = new Task(name); 
        connect(task, &Task::removed,  
       this, &MainWindow::removeTask); 
    ... 
    } 
} 
 
void MainWindow::removeTask(Task* task) 
{ 
    mTasks.removeOne(task); 
    ui->tasksLayout->removeWidget(task); 
    delete task; 
} 

MainWindow::removeTask() must match the signal signature. The connection is made when the task is created. The interesting part comes in the implementation of MainWindow::removeTask().

The task is first removed from the mTasks vector. It is then removed from tasksLayout. The last step is to delete Task. The destructor will unregister itself from centralWidget of MainWindow. In this case, we don't rely on the Qt hierarchical parent-children system for the QObject life cycle because we want to delete Task before the destruction of MainWindow.

Simplifying with the auto type and a range-based for loop

The final step to a complete CRUD of our tasks is to implement the completed task feature. We'll implement the following:

  • Click on the checkbox to mark the task as completed
  • Strike the task name
  • Update the status label in MainWindow

The checkbox click-handling follows the same pattern as removed:

// In Task.h 
signals: 
    void removed(Task* task); 
    void statusChanged(Task* task); 
private slots: 
    void checked(bool checked); 
 
// in Task.cpp 
Task::Task(const QString& name, QWidget *parent) : 
        QWidget(parent), 
        ui(new Ui::Task) 
{ 
    ... 
 
    connect(ui->checkbox, &QCheckBox::toggled,  
    this, &Task::checked); 
} 
 
... 
 
void Task::checked(bool checked) 
{ 
    QFont font(ui->checkbox->font()); 
    font.setStrikeOut(checked); 
    ui->checkbox->setFont(font); 
    emit statusChanged(this); 
} 

We define a checked(bool checked) slot that will be connected to the QCheckBox::toggled signal. In slot checked(), we strike out the checkbox text according to the bool checked value. This is done by using the QFont class. We create a copied font from checkbox->font(), modify it, and assign it back to ui->checkbox. Event if the original font was in bold or with a special size, its appearance would still be guaranteed to stay the same.

Play around with the font object in Qt Designer. Select checkbox in the Task.ui file and go to Properties Editor | QWidget | font.

The last instruction notifies MainWindow that the Task status has changed. The signal name is statusChanged, rather than checkboxChecked, in order to hide the implementation details of the task. Now add the following code in the MainWindow.h file:

// In MainWindow.h 
public: 
    void updateStatus(); 
public slots: 
    void addTask(); 
    void removeTask(Task* task); 
    void taskStatusChanged(Task* task); 
 
// In MainWindow.cpp 
MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow), 
    mTasks() 
{ 
    ... 
    updateStatus(); 
    } 
} 
 
void MainWindow::addTask() 
{ 
   ... 
   if (ok && !name.isEmpty()) { 
       ... 
       connect(task, &Task::removed, this, 
               &MainWindow::removeTask); 
       connect(task, &Task::statusChanged, this, 
               &MainWindow::taskStatusChanged); 
       mTasks.append(task); 
       ui->tasksLayout->addWidget(task); 
       updateStatus(); 
   } 
} 
 
void MainWindow::removeTask(Task* task) 
{ 
   ... 
   delete task; 
   updateStatus(); 
} 
 
void MainWindow::taskStatusChanged(Task* /*task*/) 
{ 
    updateStatus(); 
} 
 
void MainWindow::updateStatus() 
{ 
    int completedCount = 0; 
    for(auto t : mTasks)  { 
        if (t->isCompleted()) { 
            completedCount++; 
        } 
    } 
    int todoCount = mTasks.size() - completedCount; 
 
    ui->statusLabel->setText(

        QString("Status: %1 todo / %2 completed") 
                             .arg(todoCount) 
                             .arg(completedCount)); 
} 

We defined a slot called taskStatusChanged, which is connected once a task is created. The single instruction of this slot is to call updateStatus(). This function iterates through the tasks and updates statusLabel. The updateStatus() function is called upon task creation and deletion.

In updateStatus(), we meet more new C++11 semantics:

for(auto t : mTasks)  { 
    ...  
} 

The for keyword lets us loop over a range-based container. Because QVector is an iterable container, we can use it here. The range declaration (auto t) is the type and variable name that will be assigned at each iteration. The range expression (mTasks) is simply the container on which the process will be done. Qt provides a custom implementation of the for (namely, foreach) loop targeted at prior versions of C++; you don't need it anymore.

The auto keyword is another great new semantic. The compiler deduces the variable type automatically based on the initializer. It relieves a lot of pain for cryptic iterators such as this:

// without the 'auto' keyword
std::vector<Task*>::const_iterator iterator = mTasks.toStdVector().begin();

// with the 'auto' keyword, how many neurones did you save? auto autoIter = mTasks.toStdVector().begin();

Since C++14, auto can even be used for function return types. It's a fabulous tool, but use it sparingly. If you put auto, the type should be obvious from the signature name/variable name.

The auto keyword can be combined with const and references. You can write a for loop such as this: for (const auto & t : mTasks) { ... }.

Remember our half-bread lambda? With all the covered features, we can write:

auto prettyName = [] (const QString& taskName) -> QString { 
    return "-------- " + taskName.toUpper(); 
}; 
connect(ui->removeButton, &QPushButton::clicked,  
    [this, name, prettyName] { 
        qDebug() << "Trying to remove" << prettyName(name); 
        this->emit removed(this); 
}); 

Now that's something beautiful. Combining auto with lambda makes very readable code and opens up a world of possibilities.

The last item to study is the QString API. We used it in updateStatus():

ui->statusLabel->setText( 
        QString("Status: %1 todo / %2 completed") 
                             .arg(todoCount) 
                             .arg(completedCount)); 

The people behind Qt put a lot of work into making string-manipulation bearable in C++. This is a perfect example, where we replace the classic C sprintf with a more modern and robust API. Arguments are position-based only, no need to specify the type (less error-prone), and the arg(...) function accepts all kinds of types.

Take some time to skim through the QString documentation at http://doc.qt.io/qt-5/qstring.html. It shows how much you can do with this class and you'll see yourself using fewer and fewer examples of std string or even cstring.

Summary

In this chapter, we created a desktop Qt application from scratch. Qt is well known for its signal/slot mechanism and you must be confident using this paradigm. We also introduced some important C++14 features that will be used throughout this book.

It's now time to discover some qmake secrets and what really happens when you build your Qt project. In the next chapter, we will talk about how to create and organize an application with some platform-dependent code that must run on Windows, macOS, and Linux.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Unleash the power of Qt 5.11 with C++
  • Build applications using Qt Widgets (C++) or Qt Quick (QML)
  • Create cross-platform applications for mobile and desktop platforms with Qt 5

Description

Qt 5.11 is an app development framework that provides a great user experience and develops full capability applications with Qt Widgets, QML, and even Qt 3D. Whether you're building GUI prototypes or fully-fledged cross-platform GUI applications with a native look and feel, Mastering Qt 5 is your fastest, easiest, and most powerful solution. This book addresses various challenges and teaches you to successfully develop cross-platform applications using the Qt framework, with the help of well-organized projects. Working through this book, you will gain a better understanding of the Qt framework, as well as the tools required to resolve serious issues, such as linking, debugging, and multithreading. You'll start off your journey by discovering the new Qt 5.11 features, soon followed by exploring different platforms and learning to tame them. In addition to this, you'll interact with a gamepad using Qt Gamepad. Each chapter is a logical step for you to complete in order to master Qt. By the end of this book, you'll have created an application that has been tested and is ready to be shipped.

Who is this book for?

Mastering Qt 5 is for developers and programmers who want to build GUI-based applications. C++ knowledge is necessary, and knowing QT basics will help you get the most out of this book.

What you will learn

  • Create stunning UIs with Qt Widgets and Qt Quick 2
  • Develop powerful, cross-platform applications with the Qt framework
  • Design GUIs with the Qt Designer and build a library in it for UI previews
  • Handle user interaction with the Qt signal or slot mechanism in C++
  • Prepare a cross-platform project to host a third-party library
  • Use the Qt Animation framework to display stunning effects
  • Deploy mobile apps with Qt and embedded platforms
  • Interact with a gamepad using Qt Gamepad

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 27, 2018
Length: 534 pages
Edition : 2nd
Language : English
ISBN-13 : 9781788993890
Category :
Languages :
Tools :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Aug 27, 2018
Length: 534 pages
Edition : 2nd
Language : English
ISBN-13 : 9781788993890
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 192.97
End to End GUI Development with Qt5.
$99.99
Mastering Qt  5
$48.99
Qt5 C++ GUI Programming Cookbook
$43.99
Total $ 192.97 Stars icon
Banner background image

Table of Contents

15 Chapters
Get Your Qt Feet Wet Chevron down icon Chevron up icon
Discovering qmake Secrets Chevron down icon Chevron up icon
Dividing Your Project and Ruling Your Code Chevron down icon Chevron up icon
Conquering the Desktop UI Chevron down icon Chevron up icon
Dominating the Mobile UI Chevron down icon Chevron up icon
Even Qt Deserves a Slice of Raspberry Pi Chevron down icon Chevron up icon
Third-Party Libraries without a Headache Chevron down icon Chevron up icon
Animations - Its Alive, Alive! Chevron down icon Chevron up icon
Keeping Your Sanity with Multithreading Chevron down icon Chevron up icon
Need IPC? Get Your Minions to Work Chevron down icon Chevron up icon
Having Fun with Multimedia and Serialization Chevron down icon Chevron up icon
You Shall (Not) Pass with QTest Chevron down icon Chevron up icon
All Packed and Ready to Deploy Chevron down icon Chevron up icon
Qt Hat Tips and Tricks Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.1
(8 Ratings)
5 star 25%
4 star 37.5%
3 star 0%
2 star 0%
1 star 37.5%
Filter icon Filter
Top Reviews

Filter reviews by




Ahmed H. Apr 25, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I've just finished reading this book and wow! The implemented projects are pretty good at demonstrating the capabilities of Qt. I liked the variety of projects, scenarios, and target platforms.It is certainly an intermediate level book: if you know absolutely nothing about desktop/mobile/general programming then this might not be the one for you. And it certainly isn't a book for a guy who spent more then 2 years working on Qt.
Amazon Verified review Amazon
Maxim Rozhkov Jun 10, 2019
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The book completely covers the most important parts of the Qt library: signals/slots, the concept of Model/View, QML, Qt containers, multi-threading, and network programming. There are a lot of tips about using C++ 11/14, great patterns and in-depth explanations. There are many useful examples of applications, for instance – the album of photos for Windows/MacOS/Linux/Android/iOS. It would be naïve to expect, that the book contains a detailed description of C++ 14 – you should be an intermediate C++ developer if you want to clearly understand ideas from the book. Also, some topics are not enough deeply explained, because of their complexity. I spent lots of time trying to build Qt for Raspberry PI and an application for iOS/Android – there are many unexpected things the real life. Anyway, the book is awesome! The authors used vivid language – I read it as a novel. Thank you guys, for your great job!
Amazon Verified review Amazon
BRET KID Nov 01, 2020
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Good book
Amazon Verified review Amazon
Naga Prasad Jan 16, 2024
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Good introduction. A bit technical. Will suit engineers and developers.
Amazon Verified review Amazon
TB Oct 28, 2018
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
I purchased the 1st edition of this book when it was first released, and noticed a number of issues. Due to various factors I did not finish that edition. So when this edition was released recently, I noticed that it was based upon Qt 5.11.x, so I purchased it and promised myself I would diligently work through every page of the book. Normally I don't write a review on a book until I've finished working through it. While I am currently working through chapter 4 in this book, I felt it important to go ahead and write a preliminary review for people who may be contemplating the book--because there aren't any reviews at all as I write this.Overall, I feel that there is much to be learned from this book. Browsing through the table of contents, it looks very promising. And in the first four chapters I have definitely learned a few things about working with Qt--specifically about how to create projects that use sub-projects, like the "solutions vs projects" theme seen with MS Visual Studio. It's easy enough to do once you see it, but until you do...it is a bit perplexing. So that's one of the most useful things I've learned thus far in the first 3+ chapters.I will say though that there are several errors in the book, which is why I've only rated it as 4-stars so far. I am compiling a list of errata as I work through the book, and thus far I have submitted errata to the publisher for both chapters 2 and 3. This book would have definitely benefited by a good technical review, as there are many things that made it through that really shouldn't have. One piece of advice to prospective readers is to look through the book's source code files (downloadable from the publisher's website) if you have any problems understanding what the author is discussing in the chapters. The assumption is, I think, that the reader will not be typing in the source code themselves, but rather will simply be using the source code provided by the author--and in fact you really can't even complete the book without doing do, because the author doesn't actually give the implementation (in the text) for many of the class methods in the book. So unless you want to take a crack at writing the implementation for these methods yourself, you'll need to get the details from his source code files. And if you could do that, you really wouldn't need the book. This is most unfortunate, as I believe you learn much more by typing in the code yourself...especially when you're first learning the API.Anyway, please don't get the wrong idea about the book from this one review. In fact it really does seem to be an excellent book--but it could be even better had there been some rigorous technical editing done during the writing process. The errors I have found thus far have arguably made me a "better" Qt developer, because I have been forced to go investigate things for myself to actually know (for example) what detail the author has omitted or been less-than-clear about. But I've also been working in Qt for a few years now, intermittently, so this has made it a bit easier for me. I have to wonder though, how many other readers of the book will go to the same lengths.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.