Vous êtes sur la page 1sur 199

Qt5 tutorial

This is Qt5 tutorial. In this tutorial, you will learn the basics of GUI programming with Qt5 and
C++. The Qt5 tutorial is suitable of beginners and intermediate programmers. The images for the
two games can be downloded here. Note that the tutorial uses features of C++11.

Table of contents

Introduction
Strings
Date and time
Containers
Files and directories
First programs
Menus and toolbars
Layout management
Events and signals
Widgets
Widgets II
Painting
Custom widget
Snake game
Breakout game

Qt

Qt is a cross-platform application development framework. Some of the well known applications


developed with Qt are KDE, Opera, Google Earth, and Skype. Qt was first publicly released on May
1995. It is dual licensed. That means, it can be used for creating open source applications as well as
commercial ones. Qt toolkit is a very powerful toolkit. It is well established in the open source
community.
Introduction to Qt5 toolkit
In this part of the Qt5 tutorial, we will introduce the Qt5 library. We will install the Qt5 library and
create our first small Qt5 application.

Qt was initially developed by Trolltech, a Norwegian software company. In 2008 the company was
acquired by Nokia. In August 2012 a Finnish development company Digia acquired Qt software
technologies from Nokia. Meanwhile a Qt Project was created in which the development of open
source Qt continues. The website for the open source Qt toolkit can be found at qt.io. Qt is currently
being developed both by the Qt Company, a subsidiary of Digia, and the Qt Project under
open-source governance, involving individual developers and firms.

Qt
Qt is a cross-platform application development framework. Some of the well known applications
developed with Qt are KDE, Opera, Google Earth, Skype, VLC, Maya, or Mathematica. Qt was first
publicly released on May 1995. It is dual licensed. It can be used for creating open source
applications as well as commercial ones. Qt toolkit is a very powerful toolkit. It is well established
in the open source community. Thousands of open source developers use Qt all over the world.

Download and decompress

We go to the download.qt.io/official_releases/qt/ page. (Since the download links have been


changing often in the past, you might need to google for the current link.) We choose the latest Qt
5.x sources. At the time of the creation of this tutorial, the latest sources were Qt 5.5.1. Next, we are
going to install Qt from sources.

$ ls qt-everywhere-opensource-src-5.5.1.tar.gz
qt-everywhere-opensource-src-5.5.1.tar.gz

From the download page, we download the Qt5 sources. We use the TAR file. (We save ourselves
some trouble. The ZIP file has Windows line endings.)

$ tar -xzvf qt-everywhere-opensource-src-5.5.1.tar.gz

The command will decompress all the files to a directory qt-everywhere-opensource-src-5.5.1/.


$ du -hs qt-everywhere-opensource-src-5.5.1
2.0G qt-everywhere-opensource-src-5.5.1

The size of the directory is now 2 G.

$ cd qt-everywhere-opensource-src-5.5.1/

We go to the created directory. In the README file there are installation instructions. The installation
is easy and straightforward, but it takes considerable time.

Installation from sources


Before we start building Qt5, we might want to install some additional libraries. For instance, if we
want to connect to MySQL from Qt, we need to have libmysqld-dev installed on our system.

We install the library the classic way. On Unix systems, installation of a software is divided into
three steps.

Configuration
Building
Installation

$ ./configure -prefix /usr/local/qt5


Which edition of Qt do you want to use ?

Type 'c' if you want to use the Commercial Edition.


Type 'o' if you want to use the Open Source Edition.

First we run the configure script. The script will ask whether we want the commercial or open
source edition of the Qt5 library. The script will configure the library for our machine type. By
default, the Qt will be installed in /usr/local/Qt-5.5.1/ directory. This can be changed by the
-prefix parameter of the configure script. We install the library into the /usr/local/qt5/

directory. Note that the installation word has two meanings here. It is the whole process consisting
of all three steps. And it also means 'moving files to specific directories', which is the last, third step.

This is the Open Source Edition.

You are licensed to use this software under the terms of


the Lesser GNU General Public License (LGPL) versions 2.1.
You are also licensed to use this software under the terms of
the GNU General Public License (GPL) versions 3.

Type '3' to view the GNU General Public License version 3.


Type 'L' to view the Lesser GNU General Public License version 2.1.
Type 'yes' to accept this license offer.
Type 'no' to decline this license offer.

Do you accept the terms of either license? yes

Confirming license agreement.

Running configuration tests...


The test for linking against libxcb and support libraries failed!
You might need to install dependency packages, or pass -qt-xcb.

If the script fails with the above message, we either need to install some additional xcb libraries, or
run the script again with the -qt-xcb option.

$ ./configure -prefix /usr/local/qt5 -qt-xcb

With the -qt-xcb option, some libraries are built instead of being linked against the system
libraries.

...
Qt modules and options:
Qt D-Bus ............... yes (loading dbus-1 at runtime)
Qt Concurrent .......... yes
Qt GUI ................. yes
Qt Widgets ............. yes
Large File ............. yes
QML debugging .......... yes
Use system proxies ..... no
...
SQL drivers:
DB2 .................. no
InterBase ............ no
MySQL ................ yes (plugin)
OCI .................. no
ODBC ................. no
PostgreSQL ........... yes (plugin)
SQLite 2 ............. no
SQLite ............... yes (plugin, using bundled copy)
TDS .................. no
tslib .................. no
udev ................... yes
xkbcommon-x11........... yes (bundled copy, XKB config root: /usr/share/X11/xkb)
xkbcommon-evdev......... yes
zlib ................... yes (system library)
Qt is now configured for building. Just run 'make'.
Once everything is built, you must run 'make install'.
Qt will be installed into /usr/local/qt5

Prior to reconfiguration, make sure you remove any leftovers from


the previous build.

This is a partial output of the configure script. The output tells us what components are prepared to
be built. For instance, SQL drivers for MySQL and PostgreSQL are going to be created, but not for
DB2 or InterBase.

$ make

We use the make command to start the build process. The building of the Qt toolkit can take several
hours; it depends on the power of your processor.

The last step is installing, or moving files to the directories.

$ sudo make install

This command finishes the installation process. The library is now installed in /usr/local/qt5/
directory.

The last thing that we do is to add the Qt5 path to the PATH system variable. The bash users need to
edit the either the .profile file or the .bashrc file.

$ PATH=/usr/local/qt5/bin:$PATH
$ export PATH

We have added a path to the bin directory of the Qt5 library to the PATH environment variable. The
changes will be active after another login.

Installation from packages


It is easier to install Qt from packages. Linux packages usually do not contain the latest Qt version.

$ sudo apt-get install qt5-default

The above command installs Qt5 on Debian-based Linux.

Version

Our first program prints the version of the Qt5 library.

version.cpp
#include <QtCore>
#include <iostream>

int main() {

std::cout << "Qt version: " << qVersion() << std::endl;


}

The qVersion() function returns the version number of Qt at run-time as a string.

$ g++ -o version version.cpp -I/usr/local/qt5/include/QtCore -I/usr/local/qt5/include -L/usr/lo

The above command compiles the example. Note that your Qt5 library might be installed in
different location.

$ ./version
Qt version: 5.5.1

The version of the Qt5 library used throughout this tutorial is 5.5.1.

Testing a small GUI example

Finally, we write a small application. The application consists of a plain window.

simple.cpp
#include <QApplication>
#include <QWidget>

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

QApplication app(argc, argv);

QWidget window;

window.resize(250, 150);
window.setWindowTitle("Simple example");
window.show();

return app.exec();
}

To build this example, we use the qmake tool.

$ qmake -project

This command creates a project file, which has a .pro extension.

simple.pro
######################################################################
# Automatically generated by qmake (3.0) Fri Oct 30 17:11:00 2015
######################################################################
TEMPLATE = app
TARGET = simple
INCLUDEPATH += .

# Input
SOURCES += simple.cpp

QT += widgets

The Qt Widgets module is not included in the project by default. Therefore, we add the module at
the end of the file.

$ qmake
$ make

We build the program with the above commands. The qmake creates a Makefile and the make
command builds the program.

If the Qt5 installation directory is not a part of the PATH variable, we can provide the full path to the
qmake tool.

$ /usr/local/qt5/bin/qmake -project
$ /usr/local/qt5/bin/qmake
$ make

Figure: Simple example

This chapter was an introduction to the Qt5 library.


Strings in Qt5
In this chapter we will work with strings. Qt5 has a QString class for working with strings. It is very
powerful and has numerous methods.

The QString class provides a Unicode character string. It stores a string as 16-bit QChars. Each
QChar corresponds to one Unicode 4.0 character. Unlike strings in many other programming

languages, a QString can be modified.

In the examples of this chapter, we will not need the Qt GUI module; we will create command line
programs. Since Qt GUI is included by default, we can disable it by adding the QT -= gui
declaration in the project file.

First example

In the first example, we will work with a few basic methods of the QString class.

basic.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString a = "love";

a.append(" chess");
a.prepend("I ");

out << a << endl;


out << "The a string has " << a.count()
<< " characters" << endl;

out << a.toUpper() << endl;


out << a.toLower() << endl;

return 0;
}

In the code example, we initiate a QString. We append and prepend some additional text. We print
the length of the string. Finally, we print the modified string in upper and lower case.

QString a = "love";

A QString is initiated.

a.append(" chess");
a.prepend("I ");

We append and prepend text to the initial string. The string is modified in-place.

out << a << endl;

'I love chess' is printed to the terminal.

out << "The a string has " << a.count()


<< " characters" << endl;

The count() method returns the number of characters in the string. The length() and size()
methods are equivalents.

out << a.toUpper() << endl;


out << a.toLower() << endl;

These two methods return an uppercase and lowercase copy of the string. They do not modify the
string, they return a new modified copy of the string.

Output

$ ./basic
I love chess
The a string has 12 characters
I LOVE CHESS
i love chess

Initiating strings
A QString can be initiated in several ways.

init.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString str1 = "The night train";


out << str1 << endl;

QString str2("A yellow rose");


out << str2 << endl;

std::string s1 = "A blue sky";


QString str3 = s1.c_str();
out << str3 << endl;

std::string s2 = "A thick fog";


QString str4 = QString::fromLatin1(s2.data(), s2.size());
out << str4 << endl;

char s3[] = "A deep forest";


QString str5(s3);
out << str5 << endl;

return 0;
}

We present five ways of initiating a QString.

QString str1 = "The night train";

This is a traditional way of initiating a string in computer languages.

QString str2("A yellow rose");

This is an object way of initiating a QString.

std::string s1 = "A blue sky";


QString str3 = s1.c_str();

We have a string object from the C++ standard library. We use its c_str() method to generate a
null-terminated sequence of characters. This array of characters, a classic C representation of a
string, can be assigned to a QString variable.

std::string s2 = "A thick fog";


QString str4 = QString::fromLatin1(s2.data(), s2.size());

In these code lines we convert a standard C++ string to a QString. We utilise the fromLatin1()
method. It takes a pointer to the an array of characters. The pointer is returned with the data()
method of the std::string. The second parameter is the the size of the std::string.

char s3[] = "A deep forest";


QString str5(s3);

This is a C string; it is an array of chars. One of the QString constructors can take an array of chars
as a parameter.

Output

$ ./init
The night train
A yellow rose
A blue sky
A thick fog
A deep forest

Accessing string elements


A QString is a sequence of QChars. The elements of a string can be accessed using the [] operator or
the at() method.

access.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString a = "Eagle";

out << a[0] << endl;


out << a[4] << endl;

out << a.at(0) << endl;

if (a.at(5).isNull()) {
out << "Outside the range of the string" << endl;
}

return 0;
}

We print some individual characters from a specific QString.

out << a[0] << endl;


out << a[4] << endl;

We print the first and the fifth element of a string.

out << a.at(0) << endl;

With the at() method, we retrieve the first character of the string.

if (a.at(5).isNull()) {
out << "Outside the range of the string" << endl;
}

The at() method returns null if we are trying to access a character outside the range of string
characters.

Output

$ ./access
E
e
E
Outside the range of the string

The string length


There are three methods to get the length of a string. The size(), the count(), and the length()
method. All do the same thing. They return the number of characters in the specified string.

length.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString s1 = "Eagle";
QString s2 = "Eagle\n";
QString s3 = "Eagle ";
QString s4 = " ";

out << s1.length() << endl;


out << s2.length() << endl;
out << s3.length() << endl;
out << s4.length() << endl;

return 0;
}

We get the size of four strings.

QString s2 = "Eagle\n";
QString s3 = "Eagle ";

Each of these two strings has a white character.

QString s4 = " ";

This string consists of Russian letters.

Output

$ ./length
5
6
6
4

From the output we can see that the length() method counts the white characters too.
String building
Dynamic string building allows us to replace specific control characters with actual values. We use
the arg() method to do the interpolation.

building.cpp
#include <QTextStream>

int main() {

QTextStream out(stdout);

QString s1 = "There are %1 white roses";


int n = 12;

out << s1.arg(n) << endl;

QString s2 = "The tree is %1 m high";


double h = 5.65;

out << s2.arg(h) << endl;

QString s3 = "We have %1 lemons and %2 oranges";


int ln = 12;
int on = 4;

out << s3.arg(ln).arg(on) << endl;

return 0;
}

The markers which are going to be replaced begin with the % character. The following character is a
number specifying the argument. There can be multiple of arguments for a string. The arg()
method is overloaded, it can take integers, long numbers, chars, and QChars among others.

QString s1 = "There are %1 white roses";


int n = 12;

The %1 is the marker which we plan to replace. We have defined one integer.

out << s1.arg(n) << endl;

The arg() method takes an integer. The %1 marker is replaced with the value of the n variable.

QString s2 = "The tree is %1 m high";


double h = 5.65;

out << s2.arg(h) << endl;

These three lines do the same thing for a double number. The correct arg() method is called
automatically.

QString s3 = "We have %1 lemons and %2 oranges";


int ln = 12;
int on = 4;

out << s3.arg(ln).arg(on) << endl;

We can have multiple control characters. The %1 refers to the first argument, the %2 to the second.
The arg() methods are called in a consecutive chain.

Output

$ ./building
There are 12 white roses
The tree is 5.65 m high
We have 12 lemons and 4 oranges

Substrings

When doing text processing, we need to find substrings of normal strings. We have left(), mid(),
and right() methods at our disposal.

substrings.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString str = "The night train";

out << str.right(5) << endl;


out << str.left(9) << endl;
out << str.mid(4, 5) << endl;

QString str2("The big apple");


QStringRef sub(&str2, 0, 7);

out << sub.toString() << endl;

return 0;
}

We will use all three methods to find some substrings of a given string.

out << str.right(5) << endl;

With the right() method, we get five rightmost characters of the str string. The 'train' is printed.

out << str.left(9) << endl;


With the left() method, we get nine leftmost characters of the str string. The 'The night' is
printed.

out << str.mid(4, 5) << endl;

With the mid() method, we get five characters starting from the 4th position. The 'night' is printed.

QString str2("The big apple");


QStringRef sub(&str2, 0, 7);

The QStringRef class is a read-only version of a QString. Here we create a QStringRef of a portion
of the str2 string. The second parameter is the position and the third is the length of the substring.

Output

$ ./substrings
train
The night
night
The big

Looping through strings


A QString consists of QChars. We can loop through the QString to access each element of a string.

looping.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString str = "There are many stars.";

foreach (QChar qc, str) {


out << qc << " ";
}

out << endl;

for (QChar *it=str.begin(); it!=str.end(); ++it) {


out << *it << " " ;
}

out << endl;

for (int i = 0; i < str.size(); ++i) {


out << str.at(i) << " ";
}

out << endl;


return 0;
}

We show three ways to go through a QString. We add a space character between the letters as we
print them to the terminal.

foreach (QChar qc, str) {


out << qc << " ";
}

The foreach keyword is a Qt extension to the C++ language. The first parameter of the keyword is
the string element, the second one is the string.

for (QChar *it=str.begin(); it!=str.end(); ++it) {


out << *it << " " ;
}

In this code, we use iterators to go through the string.

for (int i = 0; i < str.size(); ++i) {


out << str.at(i) << " ";
}

We compute the size of the string and use the at() method to access the string elements.

Output

$ ./looping
T h e r e a r e m a n y s t a r s .
T h e r e a r e m a n y s t a r s .
T h e r e a r e m a n y s t a r s .

String comparison
The QString::compare() static method is used to compare two strings. The method returns an
integer. If the returned value is less than zero, the first string is less than the second. If it returns
zero, both strings are equal. Finally, if the returned value is greater than zero, the first string is
greater than the second. By 'less' we mean that a specific character of a string is positioned before
the other one in the character table. Strings are compared the following way: the first characters of
the two strings are compared; if they are equal, the following two characters are compared until we
find some characters that differ or we find that all characters match.

comparing.cpp
#include <QTextStream>

#define STR_EQUAL 0

int main(void) {
QTextStream out(stdout);

QString a = "Rain";
QString b = "rain";
QString c = "rain\n";

if (QString::compare(a, b) == STR_EQUAL) {
out << "a, b are equal" << endl;
} else {
out << "a, b are not equal" << endl;
}

out << "In case insensitive comparison:" << endl;

if (QString::compare(a, b, Qt::CaseInsensitive) == STR_EQUAL) {


out << "a, b are equal" << endl;
} else {
out << "a, b are not equal" << endl;
}

if (QString::compare(b, c) == STR_EQUAL) {
out << "b, c are equal" << endl;
} else {
out << "b, c are not equal" << endl;
}

c.chop(1);

out << "After removing the new line character" << endl;

if (QString::compare(b, c) == STR_EQUAL) {
out << "b, c are equal" << endl;
} else {
out << "b, c are not equal" << endl;
}

return 0;
}

We will do case sensitive and case insensitive comparison with the compare() method.

#define STR_EQUAL 0

For better code clarity, we define the STR_EQUAL constant.

QString a = "Rain";
QString b = "rain";
QString c = "rain\n";

We will be comparing these three strings.

if (QString::compare(a, b) == STR_EQUAL) {
out << "a, b are equal" << endl;
} else {
out << "a, b are not equal" << endl;
}

We compare a and b strings, they are not equal. They differ in the first character.

if (QString::compare(a, b, Qt::CaseInsensitive) == STR_EQUAL) {


out << "a, b are equal" << endl;
} else {
out << "a, b are not equal" << endl;
}

In case of case insensitive comparison, the strings are equal. The Qt::CaseInsensitive makes the
comparison case insensitive.

c.chop(1);

The chop() method removes the last character from the c string. Now the b and c strings are equal.

Output

$ ./comparing
a, b are not equal
In case insensitive comparison:
a, b are equal
b, c are not equal
After removing the new line character
b, c are equal

Converting strings
Strings often need to be converted to other data types, and vice versa. The toInt(), toFloat(),
toLong() are three QString methods which convert a string to an integer, float, and long number.

(There are more such methods.) The setNum() method converts various numeric data types to a
string. The method is overloaded and the correct one is called automatically.

Output
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString s1 = "12";
QString s2 = "15";
QString s3, s4;

out << s1.toInt() + s2.toInt() << endl;

int n1 = 30;
int n2 = 40;
out << s3.setNum(n1) + s4.setNum(n2) << endl;

return 0;
}

In the example we convert two strings to integers and add them. Then we convert two integers to
strings and concatenate them.

out << s1.toInt() + s2.toInt() << endl;

The toInt() method converts a string to an integer. We add two numbers converted froms strings.

out << s3.setNum(n1) + s4.setNum(n2) << endl;

In this case the setNum() method converts an integer to a string. We concatenate two strings.

Output

$ ./converts
27
3040

Letters
Characters are divided into various categories: digits, letters, spaces, and punctuation characters.
Each QString consists of QChars. The QChar has the isDigit(), isLetter(), isSpace(), and
isPunct() method to perform the job.

letters.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

int digits = 0;
int letters = 0;
int spaces = 0;
int puncts = 0;

QString str = "7 white, 3 red roses.";

foreach(QChar s, str) {

if (s.isDigit()) {
digits++;
} else if (s.isLetter()) {
letters++;
} else if (s.isSpace()) {
spaces++;
} else if (s.isPunct()) {
puncts++;
}
}

out << QString("There are %1 characters").arg(str.count()) << endl;


out << QString("There are %1 letters").arg(letters) << endl;
out << QString("There are %1 digits").arg(digits) << endl;
out << QString("There are %1 spaces").arg(spaces) << endl;
out << QString("There are %1 punctuation characters").arg(puncts) << endl;

return 0;
}

In the example we define a simple sentence. We will count the number of digits, letters, spaces, and
punctuation characters in the sentence.

int digits = 0;
int letters = 0;
int spaces = 0;
int puncts = 0;

We define an integer variable for each character category.

QString str = "7 white, 3 red roses.";

This is the sentence to be examined.

foreach(QChar s, str) {

if (s.isDigit()) {
digits++;
} else if (s.isLetter()) {
letters++;
} else if (s.isSpace()) {
spaces++;
} else if (s.isPunct()) {
puncts++;
}
}

We use the foreach keyword to go through the QString. Each of the elements is a QChar. We use the
methods of the QChar class to determine the categories of characters.

out << QString("There are %1 characters").arg(str.count()) << endl;


out << QString("There are %1 letters").arg(letters) << endl;
out << QString("There are %1 digits").arg(digits) << endl;
out << QString("There are %1 spaces").arg(spaces) << endl;
out << QString("There are %1 punctuation characters").arg(puncts) << endl;

Using the string interpolation, we print the numbers to the terminal.

Output

$ ./letters
There are 21 characters
There are 13 letters
There are 2 digits
There are 4 spaces
There are 2 punctuation characters

Modifying strings
Some methods (for example the toLower() method) return a new modified copy of an original
string. Other methods modify the string in-place. We will present some of them.

modify.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString str = "Lovely";


str.append(" season");

out << str << endl;

str.remove(10, 3);
out << str << endl;

str.replace(7, 3, "girl");
out << str << endl;

str.clear();

if (str.isEmpty()) {
out << "The string is empty" << endl;
}

return 0;
}

We describe four methods that modify a string in-place.

str.append(" season");

The append() method adds a new string at the end of the string.

str.remove(10, 3);

The remove() method removes 3 characters from the string, starting from position 10.

str.replace(7, 3, "girl");

The replace() method replaces 3 characters beginning at position 7 with the specified string.
str.clear();

The clear() method clears the string.

Output

$ ./modify
Lovely season
Lovely sea
Lovely girl
The string is empty

In this chapter, we have worked with strings in Qt5.

Aligning strings
It is a common requirement to have a neat output. We can use the leftJustified() and
rightJustified() methods to align our strings.

right_align.cpp
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QString field1 = "Name: ";


QString field2 = "Occupation: ";
QString field3 = "Residence: ";
QString field4 = "Marital status: ";

int width = field4.size();

out << field1.rightJustified(width, ' ') << "Robert\n";


out << field2.rightJustified(width, ' ') << "programmer\n";
out << field3.rightJustified(width, ' ') << "New York\n";
out << field4.rightJustified(width, ' ') << "single\n";

return 0;
}

The example aligns field strings to the right.

int width = field4.size();

We calculate the size of the widest string.

out << field1.rightJustified(width, ' ') << "Robert\n";

The rightJustified() method returns a string having width characters. If the string is shorter, the
rest is filled with the provided character. In our case, it is a space character.
Output

$ ./right_align
Name: Robert
Occupation: programmer
Residence: New York
Marital status: single

Escaping characters
Qt5 has a toHtmlEscaped() method, which converts a plain text string to an HTML string with
HTML metacharacters <, >, &, and " replaced by HTML named entities.

$ cat cprog.c
#include <stdio.h>

int main(void) {

for (int i=1; i<=10; i++) {


printf("Bottle %d\n", i);
}
}

This C program includes HTML metacharacters.

html_escape.cpp
#include <QTextStream>
#include <QFile>

int main(void) {

QTextStream out(stdout);

QFile file("cprog.c");

if (!file.open(QIODevice::ReadOnly)) {

qWarning("Cannot open file for reading");


return 1;
}

QTextStream in(&file);

QString allText = in.readAll();


out << allText.toHtmlEscaped() << endl;

file.close();

return 0;
}
The example reads a C program and replaced the metacharacters with their named entities.

Output

$ ./html_escape
#include &lt;stdio.h&gt;

int main(void) {

for (int i=1; i&lt;=10; i++) {


printf(&quot;Bottle %d\n&quot;, i);
}
}

In this chapter, we have worked with strings in Qt5.


Date and time in Qt5
In this part of the Qt5 C++ programming tutorial, we will talk about time and date.

Qt5 has QDate, QTime, and QDateTime classes to work with date and time. The QDate is a class for
working with a calendar date in the Gregorian calendar. It has methods for determining the date,
comparing, or manipulating dates. The QTime class works with a clock time. It provides methods for
comparing time, determining the time and various other time manipulating methods. The
QDateTime is a class that combines both QDate and QTime objects into one object.

Initialising date & time objects

Date and time objects can be initialised in two basic ways. We initialise them in the object
constructor or we can create empty objects and fill them with data later.

init.cpp
#include <QTextStream>
#include <QDate>
#include <QTime>

int main(void) {

QTextStream out(stdout);

QDate dt1(2015, 4, 12);


out << "The date is " << dt1.toString() << endl;

QDate dt2;
dt2.setDate(2015, 3, 3);
out << "The date is " << dt2.toString() << endl;

QTime tm1(17, 30, 12, 55);


out << "The time is " << tm1.toString("hh:mm:ss.zzz") << endl;

QTime tm2;
tm2.setHMS(13, 52, 45, 155);
out << "The time is " << tm2.toString("hh:mm:ss.zzz") << endl;
}

We initialise date and time object in both ways.


QDate dt1(2015, 4, 12);

The QDate object constructor takes three parameters: the year, the month, and the day.

out << "The date is " << dt1.toString() << endl;

The date is printed to the console. We use the toString() method to convert the date object into
string.

QTime tm2;
tm2.setHMS(13, 52, 45, 155);

An empty QTime object is created. We fill the object with data using the setHMS() method. The
parameters are the hours, minutes, seconds, and milliseconds.

out << "The time is " << tm2.toString("hh:mm:ss.zzz") << endl;

We print the QTime object to the console. We use a specific format that includes also the
milliseconds, which are omitted by default.

Output

$ ./init
The date is Sun Apr 12 2015
The date is Tue Mar 3 2015
The time is 17:30:12.055
The time is 13:52:45.155

Current date & time


In the following example, we print the current local time and date to the console.

curdatetime.cpp
#include <QTextStream>
#include <QTime>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate cd = QDate::currentDate();
QTime ct = QTime::currentTime();

out << "Current date is: " << cd.toString() << endl;
out << "Current time is: " << ct.toString() << endl;
}

Watch out that the file must not be called time.cpp.


QDate cd = QDate::currentDate();

The QDate::currentDate() static function returns the current date.

QTime ct = QTime::currentTime();

The QTime::currentTime() static function returns the current time.

out << "Current date is: " << cd.toString() << endl;
out << "Current time is: " << ct.toString() << endl;

We use the toString() method to convert the date and time objects to strings.

Output

$ ./curdatetime
Current date is: Fri Oct 30 2015
Current time is: 20:55:27

Comparing dates
Relational operators can be used to compare dates. We can compare their position in the calendar.

comparedates.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate dt1(2015, 4, 5);


QDate dt2(2014, 4, 5);

if (dt1 < dt2) {


out << dt1.toString() << " comes before "
<< dt2.toString() << endl;
} else {
out << dt1.toString() << " comes after "
<< dt2.toString() << endl;
}
}

The example compares two dates.

QDate dt1(2015, 4, 5);


QDate dt2(2014, 4, 5);

We have two different dates.

if (dt1 < dt2) {


out << dt1.toString() << " comes before "
<< dt2.toString() << endl;
} else {
out << dt1.toString() << " comes after "
<< dt2.toString() << endl;
}

We compare the dates with a lower than (<) comparison operator and determine which of them is
located earlier in the calendar.

Output

$ ./comparedates
Sun Apr 5 2015 comes after Sat Apr 5 2014

Comparison operators can be easily used for QTime and QDateTime objects too.

Determining a leap year


A leap year is a year containing an additional day. The reason for an extra day in the calendar is the
difference between the astronomical and the calendar year. The calendar year has exactly 365 days,
while the astronomical year, the time for the earth to make one revolution around the Sun, is
365.25 days. The difference is 6 hours which means that in four years time we are missing one day.
Because we want to have our calendar synchronised with the seasons, we add one day to February
each four years. (There are exceptions.) In the Gregorian calendar, February in a leap year has 29
days instead of the usual 28. And the year lasts 366 days instead of the usual 365.

The QDate::isLeapYear() static method determines whether a year is a leap year.

leapyear.cpp
#include <QTextStream>
#include <QDate>

int main() {

QTextStream out(stdout);

QList<int> years({2010, 2011, 2012, 2013, 2014, 2015, 2016});

foreach (int year, years) {


if (QDate::isLeapYear(year)) {
out << year << " is a leap year" << endl;
} else {
out << year << " is not a leap year" << endl;
}
}
}

In the example we have a list of years. We check each year if it is a leap year.
QList<int> years({2010, 2011, 2012, 2013, 2014, 2015, 2016});

We initialise an list of years. This is C++11 construct, therefore, we need to enable C++11. We need
to add the CONFIG += c++11, QMAKE_CXXFLAGS += -std=c++11, or QMAKE_CXXFLAGS += -std=c++0x to
the .pro file.

foreach (int year, years) {


if (QDate::isLeapYear(year)) {
out << year << " is a leap year" << endl;
} else {
out << year << " is not a leap year" << endl;
}
}

We go through the list and determine if the given year is a leap year. The QDate::isLeapYear()
returns a boolean true or false.

leapyear.pro
######################################################################
# Automatically generated by qmake (3.0) Fri Oct 30 21:01:31 2015
######################################################################

TEMPLATE = app
TARGET = leapyear
INCLUDEPATH += .
CONFIG += c++11

# Input
SOURCES += leapyear.cpp

QT -= gui

This is the project file. We add the CONFIG += c++11 declaration to enable C++11. We disable the Qt
GUI module with QT -= gui because it is not necessary for command line programs.

Output

$ ./leapyear
2010 is not a leap year
2011 is not a leap year
2012 is a leap year
2013 is not a leap year
2014 is not a leap year
2015 is not a leap year
2016 is a leap year

Predefined date formats


Qt5 has some built-in date formats. The toString() method of a QDate object takes a date format as
a parameter. The default date format used by Qt5 is Qt::TextDate.
dateformats.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate cd = QDate::currentDate();

out << "Today is " << cd.toString(Qt::TextDate) << endl;


out << "Today is " << cd.toString(Qt::ISODate) << endl;
out << "Today is " << cd.toString(Qt::SystemLocaleShortDate) << endl;
out << "Today is " << cd.toString(Qt::SystemLocaleLongDate) << endl;
out << "Today is " << cd.toString(Qt::DefaultLocaleShortDate) << endl;
out << "Today is " << cd.toString(Qt::DefaultLocaleLongDate) << endl;
out << "Today is " << cd.toString(Qt::SystemLocaleDate) << endl;
out << "Today is " << cd.toString(Qt::LocaleDate) << endl;
}

In the example, we show eight different date formats for the current date.

out << "Today is " << cd.toString(Qt::ISODate) << endl;

Here we print the current date in the Qt::ISODate format, which is an international standard for
displaying dates.

Output

$ ./dateformats
Today is Sat Oct 31 2015
Today is 2015-10-31
Today is 10/31/15
Today is Saturday, October 31, 2015
Today is 10/31/15
Today is Saturday, October 31, 2015
Today is 10/31/15
Today is 10/31/15

Custom date formats


A date can be represented in a variety of other formats. In Qt5 we can create our custom date
formats, too. Another version of the toString() method takes a format string where we can use
various format specifiers. For example the d specifier stands for a day as a number without a
leading zero. The dd specifier stands for a day as a number with a leading zero. The following table
lists available date format expressions:

Ex pression Ou tpu t

d The day as a number without a leading zero (1 to 31)


Ex pression Ou tpu t

dd The day as a number with a leading zero (01 to 31)

The abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses


ddd
QDate::shortDayName().

The long localized day name (e.g. 'Monday' to 'Sunday'). Uses


dddd
QDate::longDayName().

M The month as a number without a leading zero (1 to 12)

MM The month as a number with a leading zero (01 to 12)

The abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses


MMM
QDate::shortMonthName().

The long localized month name (e.g. 'January' to 'December'). Uses


MMMM
QDate::longMonthName().

yy The year as two digit number (00 to 99)

The year as four digit number. If the year is negative, a minus sign is
yyyy
prepended in addition.

Table: Date format specifiers

customdateformats.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate cd = QDate::currentDate();

out << "Today is " << cd.toString("yyyy-MM-dd") << endl;


out << "Today is " << cd.toString("yy/M/dd") << endl;
out << "Today is " << cd.toString("d. M. yyyy") << endl;
out << "Today is " << cd.toString("d-MMMM-yyyy") << endl;
}

We have four custom date formats.

out << "Today is " << cd.toString("yyyy-MM-dd") << endl;

This is the international date format. The parts of the date are separated by a dash character. The
yyyy is a year having four digits. The MM is the month as a number with a leading zero (01 to 12).

And the dd is the day as a number with a leading zero (01 to 31).

out << "Today is " << cd.toString("yy/M/dd") << endl;


This is another common date format. The parts are separated by a slash (/) character. The M
specifier stands for a month as a number without a leading zero (1 to 12).

out << "Today is " << cd.toString("d. M. yyyy") << endl;

This date format is used in Slovakia. The parts are separated by a dot character. The day and month
are without leading zeros. First is the day, then comes the month, and the last is the year.

Output

$ ./customdateformats
Today is 2015-10-31
Today is 15/10/31
Today is 31. 10. 2015
Today is 31-October-2015

Predefined time formats


Time has some predefined formats. The standard format specifiers are identical to those used in
the date formats. The default time format used by Qt5 is Qt::TextDate.

timeformats.cpp
#include <QTextStream>
#include <QTime>

int main(void) {

QTextStream out(stdout);

QTime ct = QTime::currentTime();

out << "The time is " << ct.toString(Qt::TextDate) << endl;


out << "The time is " << ct.toString(Qt::ISODate) << endl;
out << "The time is " << ct.toString(Qt::SystemLocaleShortDate) << endl;
out << "The time is " << ct.toString(Qt::SystemLocaleLongDate) << endl;
out << "The time is " << ct.toString(Qt::DefaultLocaleShortDate) << endl;
out << "The time is " << ct.toString(Qt::DefaultLocaleLongDate) << endl;
out << "The time is " << ct.toString(Qt::SystemLocaleDate) << endl;
out << "The time is " << ct.toString(Qt::LocaleDate) << endl;
}

In the example, we show eight different time formats for the current time.

out << "The time is " << ct.toString(Qt::ISODate) << endl;

Here we print the current time in the Qt::ISODate format, which is an international standard for
displaying times.

Output

$ ./timeformats
The time is 15:58:26
The time is 15:58:26
The time is 3:58 PM
The time is 3:58:26 PM CET
The time is 3:58 PM
The time is 3:58:26 PM CET
The time is 3:58 PM
The time is 3:58 PM

Custom time formats


We can create additional time formats. We build a custom time format where we use time format
specifiers. The following table gives a list of available format expressions.

Ex pression Ou tpu t

h the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)

hh the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)

H the hour without a leading zero (0 to 23, even with AM/PM display)

HH the hour with a leading zero (00 to 23, even with AM/PM display)

m the minute without a leading zero (0 to 59)

mm the minute with a leading zero (00 to 59)

s the second without a leading zero (0 to 59)

ss the second with a leading zero (00 to 59)

z the milliseconds without leading zeroes (0 to 999)

zzz the milliseconds with leading zeroes (000 to 999)

AP or A use AM/PM display. AP will be replaced by either "AM" or "PM".

ap or a use am/pm display. ap will be replaced by either "am" or "pm".

t the timezone (for example "CEST")

Table: Time format specifiers

customtimeformats.cpp
#include <QTextStream>
#include <QTime>

int main(void) {

QTextStream out(stdout);

QTime ct = QTime::currentTime();
out << "The time is " << ct.toString("hh:mm:ss.zzz") << endl;
out << "The time is " << ct.toString("h:m:s a") << endl;
out << "The time is " << ct.toString("H:m:s A") << endl;
out << "The time is " << ct.toString("h:m AP") << endl;

out << "The version of Qt5 is " << qVersion() << endl;
}

We have four custom time formats.

out << "The time is " << ct.toString("hh:mm:ss.zzz") << endl;

In this format, we have hour, minute, and second with a leading zero. We also add the milliseconds
with leading zeroes.

out << "The time is " << ct.toString("h:m:s a") << endl;

This time format specifier uses hour, minute, and second without a leading zero and adds am/pm
period identifiers.

Output

$ ./customtimeformats
The time is 16:23:43.542
The time is 4:23:43 pm
The time is 16:23:43 PM
The time is 4:23 PM

Retrieving the weekday


The dayOfWeek() method returns a number which represents a day of a week, where 1 is Monday
and 7 is Sunday.

weekday.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate cd = QDate::currentDate();
int wd = cd.dayOfWeek();

out << "Today is " << QDate::shortDayName(wd) << endl;


out << "Today is " << QDate::longDayName(wd) << endl;
}

In the example we print the short and long names of the current weekday.

QDate cd = QDate::currentDate();
We get the current date.

int wd = cd.dayOfWeek();

From the current date we get the day of week.

out << "Today is " << QDate::shortDayName(wd) << endl;

With the QDate::shortDayName() static method we get the short name of the weekday.

out << "Today is " << QDate::longDayName(wd) << endl;

Using the QDate::longDayName() static method we get the long name of the weekday.

Output

$ ./weekday
Today is Sat
Today is Saturday

Number of days
We can compute the number of days in a particular month using the daysInMonth() method and
the number of days in a year using the daysInYear() method.

nofdays.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);
QList<QString> months;

months.append("January");
months.append("February");
months.append("March");
months.append("April");
months.append("May");
months.append("June");
months.append("July");
months.append("August");
months.append("September");
months.append("October");
months.append("November");
months.append("December");

QDate dt1(2015, 9, 18);


QDate dt2(2015, 2, 11);
QDate dt3(2015, 5, 1);
QDate dt4(2015, 12, 11);
QDate dt5(2015, 1, 21);

out << "There are " << dt1.daysInMonth() << " days in "
<< months.at(dt1.month()-1) << endl;
out << "There are " << dt2.daysInMonth() << " days in "
<< months.at(dt2.month()-1) << endl;
out << "There are " << dt3.daysInMonth() << " days in "
<< months.at(dt3.month()-1) << endl;
out << "There are " << dt4.daysInMonth() << " days in "
<< months.at(dt4.month()-1) << endl;
out << "There are " << dt5.daysInMonth() << " days in "
<< months.at(dt5.month()-1) << endl;

out << "There are " << dt1.daysInYear() << " days in year "
<< QString::number(dt1.year()) << endl;
}

Five date objects are created. We compute the number of days in those months and in a particular
year.

QDate dt1(2015, 9, 18);


QDate dt2(2015, 2, 11);
QDate dt3(2015, 5, 1);
QDate dt4(2015, 12, 11);
QDate dt5(2015, 1, 21);

Five QDate objects are created. Each of them represents a different date.

out << "There are " << dt1.daysInMonth() << " days in "
<< months.at(dt1.month()-1) << endl;

We use the daysInMonth() method to get the number of days in the date object.

out << "There are " << dt1.daysInYear() << " days in year "
<< QString::number(dt1.year()) << endl;

And here, we get the number of days in a year using the daysInYear() method for the date object.

Output

$ ./nofdays
There are 30 days in September
There are 28 days in February
There are 31 days in May
There are 31 days in December
There are 31 days in January
There are 365 days in year 2015

Checking validity of a date


There is a isValid() method which checks whether a date is valid.
validity.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QList<QDate> dates({QDate(2015, 5, 11), QDate(2015, 8, 1),


QDate(2015, 2, 30)});

for (int i=0; i < dates.size(); i++) {

if (dates.at(i).isValid()) {
out << "Date " << i+1 << " is a valid date" << endl;
} else {
out << "Date " << i+1 << " is not a valid date" << endl;
}
}
}

In the example we check the validity of three days.

QList<QDate> dates({QDate(2015, 5, 11), QDate(2015, 8, 1),


QDate(2015, 2, 30)});

The first two days are valid. The third one is invalid. February has 28 or 29 days.

if (dates.at(i).isValid()) {
out << "Date " << i+1 << " is a valid date" << endl;
} else {
out << "Date " << i+1 << " is not a valid date" << endl;
}

Depending on the outcome of the isValid() method, we print a message about a validity of a date
to the console.

Output

$ ./validity
Date 1 is a valid date
Date 2 is a valid date
Date 3 is not a valid date

Days to, days from


We can easily calculate a date n days from a particular date. We use the addDays() method. The
daysTo() method returns the number of days to a chosen date.

daystofrom.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate dt(2015, 5, 11);


QDate nd = dt.addDays(55);

QDate xmas(2015, 12, 24);

out << "55 days from " << dt.toString() << " is "
<< nd.toString() << endl;
out << "There are " << QDate::currentDate().daysTo(xmas)
<< " days till Christmas" << endl;
}

We get a date 55 day later from May 11, 2015. We also get the number of days till Christmas.

QDate dt(2015, 5, 11);


QDate nd = dt.addDays(55);

The addDays() method returns a QDate which is 55 days after the given date.

QDate xmas(2015, 12, 24);


...
out << "There are " << QDate::currentDate().daysTo(xmas)
<< " days till Christmas" << endl;

We use the daysTo() method to calculate the number of days until Christmas.

Output

$ ./daystofrom
55 days from Mon May 11 2015 is Sun Jul 5 2015
There are 54 days till Christmas

QDateTime class
The QDateTime object contains a calendar date and a clock time. It is a combination of the QDate and
QTime classes. It has many similar methods and the usage is identical to those two classes.

datetime.cpp
#include <QTextStream>
#include <QDateTime>

int main(void) {

QTextStream out(stdout);
QDateTime cdt = QDateTime::currentDateTime();

out << "The current datetime is " << cdt.toString() << endl;
out << "The current date is " << cdt.date().toString() << endl;
out << "The current time is " << cdt.time().toString() << endl;
}

The example retrieves the current datetime.

out << "The current datetime is " << cdt.toString() << endl;

This line of code prints the current datetime to the terminal.

out << "The current date is " << cdt.date().toString() << endl;

This line retrieves the date portion of the datetime object using the date() method.

Output

$ ./datetime
The current datetime is Sat Oct 31 17:10:50 2015
The current date is Sat Oct 31 2015
The current time is 17:10:50

Julian day

A Julian day refers to a continuous count of days since the beginning of the Julian Period. It is used
primarily by astronomers. It should not be confused with the Julian calendar. The Julian Period
started in 4713 BC. The Julian day number 0 is assigned to the day starting at noon on January 1,
4713 BC. The Julian Day Number (JDN) is the number of days elapsed since the beginning of this
period. The Julian Date (JD) of any instant is the Julian day number for the preceding noon plus
the fraction of the day since that instant. (Qt5 does not compute this fraction.) Apart from
astronomy, Julian dates are often used by military and mainframe programs.

julianday.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate cd = QDate::currentDate();

out << "Gregorian date for today: " << cd.toString(Qt::ISODate) << endl;
out << "Julian day for today: " << cd.toJulianDay() << endl;
}

In the example, we compute the Gregorian date and the Julian day for today.

out << "Julian day for today: " << cd.toJulianDay() << endl;

The Julian day is returned with the toJulianDay() method.


Output

$ ./julianday
Gregorian date for today: 2015-10-31
Julian day for today: 2457327

With Julian date, it is easy to do calculations.

battles.cpp
#include <QTextStream>
#include <QDate>

int main(void) {

QTextStream out(stdout);

QDate bordate(1812, 9, 7);


QDate slavdate(1805, 12, 2);

QDate cd = QDate::currentDate();

int j_today = cd.toJulianDay();


int j_borodino = bordate.toJulianDay();
int j_slavkov = slavdate.toJulianDay();

out << "Days since Slavkov battle: " << j_today - j_slavkov << endl;
out << "Days since Borodino battle: " << j_today - j_borodino << endl;
}

The example counts the number of days passed since two historical events.

QDate bordate(1812, 9, 7);


QDate slavdate(1805, 12, 2);

We have two dates of battles of the Napoleonic era.

int j_today = cd.toJulianDay();


int j_borodino = bordate.toJulianDay();
int j_slavkov = slavdate.toJulianDay();

We compute the Julian days for today and for the Battles of Slavkov and Borodino.

out << "Days since Slavkov battle: " << j_today - j_slavkov << endl;
out << "Days since Borodino battle: " << j_today - j_borodino << endl;

We compute the number of days passed since the two battles.

Output

$ date
Sat Oct 31 20:07:32 CET 2015
$ ./battles
Days since Slavkov battle: 76669
Days since Borodino battle: 74198

On October 31, 2015, 76669 days have passed since the Battle of Slavkov and 74198 since the battle
of Borodino.

UTC time
Our planet is a sphere. It revolves round its axis. The Earth rotates towards the east. So the Sun
rises at different times in different locations. The Earth rotates once in about 24 hours. Therefore,
the world was divided into 24 time zones. In each time zone, there is a different local time. This
local time is often further modified by the daylight saving.

There is a pragmatic need for one global time. One global time helps to avoid confusion about time
zones and daylight saving time. The UTC (Universal Coordinated time) was chosen to be the
primary time standard. UTC is used in aviation, weather forecasts, flight plans, air traffic control
clearances, and maps. Unlike local time, UTC does not change with a change of seasons.

utclocal.cpp
#include <QTextStream>
#include <QDateTime>

int main(void) {

QTextStream out(stdout);

QDateTime cdt = QDateTime::currentDateTime();

out << "Universal datetime: " << cdt.toUTC().toString() << endl;


out << "Local datetime: " << cdt.toLocalTime().toString() << endl;
}

In the example we compute the current datetime. We express the datetime in UTC datetime and
local datetime.

out << "Universal datetime" << cdt.toUTC().toString() << endl;

The toUTC() method is used to get the UTC datetime.

out << "Local datetime" << cdt.toLocalTime().toString() << endl;

The toLocalTime() is used to get the local datetime.

Output

$ ./utclocal
Universal datetime: Sat Oct 31 19:09:44 2015 GMT
Local datetime: Sat Oct 31 20:09:44 2015

The example was run in Bratislava, which has Central European Time (CET)—UTC + 1 hour.
The Unix epoch
An epoch is an instant in time chosen as the origin of a particular era. For example in western
Christian countries the time epoch starts from day 0, when Jesus was born. Another example is the
French Republican Calendar which was used for twelve years. The epoch was the beginning of the
Republican Era which was proclaimed on September 22, 1792, the day the First Republic was
declared and the monarchy abolished. Computers have their epochs too. One of the most popular is
the Unix time. The Unix epoch is the time 00:00:00 UTC on 1 January 1970 (or
1970-01-01T00:00:00Z ISO 8601). The date and time in a computer is determined according to the
number of seconds or clock ticks that have elapsed since the defined epoch for that computer or
platform.

$ date +%s
1446318984

Unix date command can be used to get the Unix time. At this particular moment, 1446318984
seconds have passed since the Unix epoch.

unixepoch.cpp
#include <QTextStream>
#include <QDateTime>
#include <ctime>

int main(void) {

QTextStream out(stdout);

time_t t = time(0);
out << t << endl;

QDateTime dt;
dt.setTime_t(t);
out << dt.toString() << endl;

QDateTime cd = QDateTime::currentDateTime();
out << cd.toTime_t() << endl;
}

In the example, we use two Qt5 functions to get the Unix time and convert it to the human readable
form.

#include <ctime>

We include the standard C++ time header file.

time_t t = time(0);
out << t << endl;
With the standard C++ time() command, we get the Unix time.

QDateTime dt;
dt.setTime_t(t);
out << dt.toString() << endl;

The setTime_t() method is used to convert the Unix time into the DateTime, which is formatted to
human readable form.

QDateTime cd = QDateTime::currentDateTime();
out << cd.toTime_t() << endl;

The Qt5's toTime_t() method can be also used to get the Unix time.

Output

$ ./unixepoch
1446319003
Sat Oct 31 20:16:43 2015
1446319003

In this chapter, we have worked with time and date.


Containers in Qt5
In this part of the Qt5 tutorial, we will talk about containers in Qt5. The following containers are
mentioned: QVector, QList, QStringList, QSet, and QMap.

Containers are general-purpose classes that store items of a given type in memory. C++ has the
Standard Template Library (STL), which has its own containers. It Qt, we can use Qt containers or
STL containers.

There are two kinds of containers: sequential and associative. Sequential containers store items one
after another, whereas associative containers store key-value pairs. QList, QVector, QLinkedList
belong to sequential containers; QMap and QHash are examples of associative containers.

QVector
QVector is a template class that provides a dynamic array. It stores its items in adjacent memory

locations and provides fast index-based access. For large vectors, inserting operations are slower
and QList container is recommended instead.

myvector.cpp
#include <QVector>
#include <QTextStream>

int main(void) {

QTextStream out(stdout);

QVector<int> vals = {1, 2, 3, 4, 5};

out << "The size of the vector is: " << vals.size() << endl;

out << "The first item is: " << vals.first() << endl;
out << "The last item is: " << vals.last() << endl;

vals.append(6);
vals.prepend(0);

out << "Elements: ";

for (int val : vals) {


out << val << " ";
}

out << endl;

return 0;
}

The example works with a vector of integers.

QVector<int> vals = {1, 2, 3, 4, 5};

A vector of integers is created.

out << "The size of the vector is: " << vals.size() << endl;

The size() method gives the size of the vector—the number of items in the vector.

out << "The first item is: " << vals.first() << endl;

The first item is retrieved with the first() method.

out << "The last item is: " << vals.last() << endl;

The last item of the vector is found with the last() method.

vals.append(6);

The append() method inserts the value at the end of the vector.

vals.prepend(0);

The prepend() method inserts the value at the beginning of the vector.

for (int val : vals) {


out << val << " ";
}

We go through the vector in the for loop and print its contents.

Output

$ ./myvector
The size of the vector is: 5
The first item is: 1
The last item is: 5
Elements: 0 1 2 3 4 5 6

QList
QList is a container for creating a list of elements. It is similar to QVector. It stores a list of values

and provides fast index-based access as well as fast insertions and removals. It is one of the most
commonly used containers in Qt.

mylist.cpp
#include <QTextStream>
#include <QList>
#include <algorithm>

int main(void) {

QTextStream out(stdout);

QList<QString> authors = {"Balzac", "Tolstoy",


"Gulbranssen", "London"};

for (int i=0; i < authors.size(); ++i) {

out << authors.at(i) << endl;


}

authors << "Galsworthy" << "Sienkiewicz";

out << "***********************" << endl;

std::sort(authors.begin(), authors.end());

out << "Sorted:" << endl;


for (QString author : authors) {

out << author << endl;


}
}

The example presents the QList container.

QList<QString> authors = {"Balzac", "Tolstoy",


"Gulbranssen", "London"};

A QList container is created. It stores the names of writers.

for (int i=0; i < authors.size(); ++i) {

out << authors.at(i) << endl;


}

In a for loop, we go through the container and print its elements. The at() method returns the item
at the given index.

authors << "Galsworthy" << "Sienkiewicz";


The << operator is used to insert two new items into the list.

std::sort(authors.begin(), authors.end());

The std::sort() method sorts the list in ascending order.

out << "Sorted:" << endl;


for (QString author : authors) {

out << author << endl;


}

Now we print the sorted list.

Output

$ ./mylist
Balzac
Tolstoy
Gulbranssen
London
***********************
Sorted:
Balzac
Galsworthy
Gulbranssen
London
Sienkiewicz
Tolstoy

QStringList
QStringList is a convenience container that provides a list of strings. It has fast index-based access

as well as fast insertions and removals.

mystringlist.cpp
#include <QTextStream>
#include <QList>

int main(void) {

QTextStream out(stdout);

QString string = "coin, book, cup, pencil, clock, bookmark";


QStringList items = string.split(",");
QStringListIterator it(items);

while (it.hasNext()) {
out << it.next().trimmed() << endl;
}
}
In the example, we create a list of strings from a string and print the elements into the console.

QString string = "coin, book, cup, pencil, clock, bookmark";


QStringList items = string.split(",");

The QString's split() method cuts the string into substrings according to the provided separator.
The substrings are returned in a list.

QStringListIterator it(items);

QStringListIterator provides a Java-style const iterator for QStringList.

while (it.hasNext()) {
out << it.next().trimmed() << endl;
}

With the created iterator, we print the elements of the list to the terminal. The trimmed() method
trims the white space in the string element.

Output

$ ./mystringlist
coin
book
cup
pencil
clock
bookmark

QSet
QSet provides a single-valued mathematical set with fast lookups. The values are stored in an

unspecified order.

myset.cpp
#include <QSet>
#include <QList>
#include <QTextStream>
#include <algorithm>

int main(void) {

QTextStream out(stdout);

QSet<QString> cols1 = {"yellow", "red", "blue"};


QSet<QString> cols2 = {"blue", "pink", "orange"};

out << "There are " << cols1.size() << " values in the set" << endl;

cols1.insert("brown");
out << "There are " << cols1.size() << " values in the set" << endl;

cols1.unite(cols2);

out << "There are " << cols1.size() << " values in the set" << endl;

for (QString val : cols1) {


out << val << endl;
}

QList<QString> lcols = cols1.values();


std::sort(lcols.begin(), lcols.end());

out << "*********************" << endl;


out << "Sorted:" << endl;

for (QString val : lcols) {


out << val << endl;
}

return 0;
}

The QSet is used to store colours in the example. It makes no sense to have one colour value
specified more times.

QSet<QString> cols1 = {"yellow", "red", "blue"};


QSet<QString> cols2 = {"blue", "pink", "orange"};

We have two sets of colour values. Blue colour is located in both sets.

out << "There are " << cols1.size() << " values in the set" << endl;

The size() method returns the size of the set.

cols1.insert("brown");

We add a new value to a set with the insert() method.

cols1.unite(cols2);

The unite(( method performs a union of two sets. The cols1 set will have all items inserted from
cols2 set that are not already present; in our case, all except for the colour blue.

for (QString val : cols1) {


out << val << endl;
}

With the for loop, we print all the items in the cols1 set.

QList<QString> lcols = cols1.values();


std::sort(lcols.begin(), lcols.end());

Sorting of a set is not supported. We can create a list out of a set and sort it. The values() method
returns a new QList containing the elements in the set. The order of the elements in the QList is
undefined.

Output

$ ./myset
There are 3 values in the set
There are 4 values in the set
There are 6 values in the set
pink
orange
brown
blue
yellow
red
*********************
Sorted:
blue
brown
orange
pink
red
yellow

QMap
QMap is an associative array (dictionary) that stores key-value pairs. It provides fast lookup of the

value associated with a key.

myqmap.cpp
#include <QTextStream>
#include <QMap>

int main(void) {

QTextStream out(stdout);

QMap<QString, int> items = { {"coins", 5}, {"books", 3} };

items.insert("bottles", 7);

QList<int> values = items.values();

out << "Values:" << endl;

for (int val : values) {


out << val << endl;
}

QList<QString> keys = items.keys();


out << "Keys:" << endl;
for (QString key : keys) {
out << key << endl;
}

QMapIterator<QString, int> it(items);

out << "Pairs:" << endl;

while (it.hasNext()) {
it.next();
out << it.key() << ": " << it.value() << endl;
}
}

In the example, we have a dictionary where we map string keys to integer values.

QMap<QString, int> items = { {"coins", 5}, {"books", 3} };

A QMap is created. It has two pairs.

items.insert("bottles", 7);

A new pair is inserted with the insert() method.

QList<int> values = items.values();

out << "Values:" << endl;

for (int val : values) {


out << val << endl;
}

We get all the values of the dictionary and print them to the console. The values() method returns
a list of map values.

QList<QString> keys = items.keys();

out << "Keys:" << endl;


for (QString key : keys) {
out << key << endl;
}

Likewise, we print all the keys of the dictionary. The keys() method returns a list containing all the
keys in the dictionary.

QMapIterator<QString, int> it(items);

QMapIterator is a Java-style iterator for a QMap. It can be used to iterate over elements of a map.

while (it.hasNext()) {
it.next();
out << it.key() << ": " << it.value() << endl;
}

With the help of the iterator, we walk over all elements of the map. The key() method returns the
current key and the value() method returns the current value.

Output

$ ./myqmap
Values:
3
7
5
Keys:
books
bottles
coins
Pairs:
books: 3
bottles: 7
coins: 5

Custom class sorting


In the following example, we are going to sort objects of a custom class in a QList.

book.h
class Book {

public:
Book(QString, QString);
QString getAuthor() const;
QString getTitle() const;

private:
QString author;
QString title;
};

This is the header file for our custom Book class.

book.cpp
#include <QString>
#include "book.h"

Book::Book(QString auth, QString tit) {

author = auth;
title = tit;
}
QString Book::getAuthor() const {

return author;
}

QString Book::getTitle() const {

return title;
}

This is the implementation of the Book class; we have two accessor methods.

sortcustomclass.cpp
#include <QTextStream>
#include <QList>
#include <algorithm>
#include "book.h"

bool compareByTitle(const Book &b1, const Book &b2) {

return b1.getTitle() < b2.getTitle();


}

int main(void) {

QTextStream out(stdout);

QList<Book> books = {
Book("Jack London", "The Call of the Wild"),
Book("Honoré de Balzac", "Father Goriot"),
Book("Leo Tolstoy", "War and Peace"),
Book("Gustave Flaubert", "Sentimental education"),
Book("Guy de Maupassant", "Une vie"),
Book("William Shakespeare", "Hamlet")
};

std::sort(books.begin(), books.end(), compareByTitle);

for (Book book : books) {


out << book.getAuthor() << ": " << book.getTitle() << endl;
}
}

In the example, we create a few book objects and sort them with the std::sort algorithm.

bool compareByTitle(const Book &b1, const Book &b2) {

return b1.getTitle() < b2.getTitle();


}

The compareByTitle() is a comparison function used by the sort algorithm.

std::sort(books.begin(), books.end(), compareByTitle);


The std::sort algorithm sorts the books in the list by the book's title.

Output

$ ./sortcustomclass
Honoré de Balzac: Father Goriot
William Shakespeare: Hamlet
Gustave Flaubert: Sentimental education
Jack London: The Call of the Wild
Guy de Maupassant: Une vie
Leo Tolstoy: War and Peace

In this chapter, we have worked with Qt's containers.


Working with files and directories in Qt5
In this part of the Qt5 C++ programming tutorial, we work with files and directories.

QFile, QDir, and QFileInfo are fundamental classes for working with files in Qt5. QFile provides an

interface for reading from and writing to files. QDir provides access to directory structures and their
contents. QFileInfo provides system-independent file information, including file's name and
position in the file system, access time and modification time, permissions, or file ownership.

File size
In the next example, we determine the size of a file.

file_size.cpp
#include <QTextStream>
#include <QFileInfo>

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

QTextStream out(stdout);

if (argc != 2) {

qWarning("Usage: file_size file");


return 1;
}

QString filename = argv[1];

if (!QFile(filename).exists()) {

qWarning("The file does not exist");


return 1;
}

QFileInfo fileinfo(filename);

qint64 size = fileinfo.size();

QString str = "The size is: %1 bytes";

out << str.arg(size) << endl;


}

The size of the file is determined with the QFileInfo's size() method.

QString filename = argv[1];

The name of the file is passed as an argument to the program.

if (!QFile(filename).exists()) {
qWarning("The file does not exist");
return 1;
}

The existence of the file is checked with the exists() method of the QFile class. If it does not exist,
we issue a warning and terminate the program.

QFileInfo fileinfo(filename);

An instance of the QFileInfo is created.

qint64 size = fileinfo.size();

The file size is determined with the size() method. The qint64 is a type guaranteed to be 64-bit on
all platforms supported by Qt.

QString str = "The size is: %1 bytes";

out << str.arg(size) << endl;

The outcome is printed to the console.

Output

$ ./file_size Makefile
The size is: 28029 bytes

Reading file contents


In order to read the contents of a file, we must first open the file for reading. Then an input file
stream is created; from this stream, the data is read.

read_file.cpp
#include <QTextStream>
#include <QFile>

int main(void) {

QTextStream out(stdout);
QFile file("colours");

if (!file.open(QIODevice::ReadOnly)) {

qWarning("Cannot open file for reading");


return 1;
}

QTextStream in(&file);

while (!in.atEnd()) {

QString line = in.readLine();


out << line << endl;
}

file.close();
}

The example reads data from the colours file. The file contains the names of eight colours.

QFile file("colours");

An instance of the QFile object is created.

if (!file.open(QIODevice::ReadOnly)) {

qWarning("Cannot open file for reading");


return 1;
}

The QFile's open() method opens the file in the read-only mode. If the method fails, we issue a
warning and terminate the program.

QTextStream in(&file);

An input stream is created. The QTextStream receives the file handle. The data will be read from
this stream.

while (!in.atEnd()) {

QString line = in.readLine();


out << line << endl;
}

In the while loop we read the file line by line until the end of the file. The atEnd() method returns
true if there is no more data to be read from the stream. The readLine() method reads one line
from the stream.

file.close();

The close() method flushes the data and closes the file handle.
Output

$ ./read_file colours
red
green
blue
yellow
brown
white
black
violet

Writing to a file
In order to write to a file, we open the file in the write mode, create an output stream directed to
the file, and use a write operator to write to that stream.

write2file.cpp
#include <QTextStream>
#include <QFile>

int main(void) {

QTextStream out(stdout);

QString filename = "distros";


QFile file(filename);

if (file.open(QIODevice::WriteOnly)) {

QTextStream out(&file);
out << "Xubuntu" << endl;
out << "Arch" << endl;
out << "Debian" << endl;
out << "Redhat" << endl;
out << "Slackware" << endl;

} else {

qWarning("Could not open file");


}

file.close();
}

The example writes the names of five Linux distributions to the file name called distros.

QString filename = "distros";


QFile file(filename);

The QFile object is created with the provided file name.

if (file.open(QIODevice::WriteOnly)) {
With the open() method, we open the file in the write-only method.

QTextStream out(&file);

This line creates a QTextStream that operates on a file handle. In other words, the stream of data to
be written is directed to the file.

out << "Xubuntu" << endl;


out << "Arch" << endl;
out << "Debian" << endl;
out << "Redhat" << endl;
out << "Slackware" << endl;

The data is written with the << operator.

file.close();

In the end, the file handle is closed.

Output

$ ./write2file
$ cat distros
Xubuntu
Arch
Debian
Redhat
Slackware

Copying a file
When we copy a file, we create an exact reproduction of the file with a different name or in a
different place of the filesystem.

copy_file.cpp
#include <QTextStream>
#include <QFile>

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

QTextStream out(stdout);

if (argc != 3) {

qWarning("Usage: copyfile source destination");


return 1;
}

QString source = argv[1];

if (!QFile(source).exists()) {
qWarning("The source file does not exist");
return 1;
}

QString destin(argv[2]);

QFile::copy(source, destin);
}

The example creates a copy of the provided file with the QFile::copy() method.

if (argc != 3) {

qWarning("Usage: copyfile source destination");


return 1;
}

The program takes two parameters; if they are not given, it ends with a warning message.

QString source = argv[1];

From the command line arguments of the program, we get the name of the source file.

if (!QFile(source).exists()) {
qWarning("The source file does not exist");
return 1;
}

We check for the existence of the source file with the QFile's exists() method. If it does not exist,
we terminate the program with a warning message.

QString destin(argv[2]);

We get the destination file name.

QFile::copy(source, destin);

The source file is copied with the QFile::copy() method. The first parameter is the source file
name, the second parameter is the destination file name.

File owner and group

Each file has a user who is its owner. A file also belongs to a group of users for better management
and protection of files.

owner.cpp
#include <QTextStream>
#include <QFileInfo>

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


QTextStream out(stdout);

if (argc != 2) {

qWarning("Usage: owner file");


return 1;
}

QString filename = argv[1];

QFileInfo fileinfo(filename);

QString group = fileinfo.group();


QString owner = fileinfo.owner();

out << "Group: " << group << endl;


out << "Owner: " << owner << endl;
}

The example prints the owner and the primary group of the given file.

QFileInfo fileinfo(filename);

An instance of the QFileInfo class is created. Its parameter is the file name given as a command
line argument.

QString group = fileinfo.group();

The primary group of the file is determined with the QFileInfo's group() method.

QString owner = fileinfo.owner();

The owner of the file is determined with the QFileInfo's owner() method.

Output

$ touch myfile
$ ./owner myfile
Group: janbodnar
Owner: janbodnar

Last read, last modified


Files store information about the last time they were read or modified. To get this information, we
use the QFileInfo class.

file_times.cpp
#include <QTextStream>
#include <QFileInfo>
#include <QDateTime>
int main(int argc, char *argv[]) {

QTextStream out(stdout);

if (argc != 2) {

qWarning("Usage: file_times file");


return 1;
}

QString filename = argv[1];

QFileInfo fileinfo(filename);

QDateTime last_rea = fileinfo.lastRead();


QDateTime last_mod = fileinfo.lastModified();

out << "Last read: " << last_rea.toString() << endl;


out << "Last modified: " << last_mod.toString() << endl;
}

The example prints the last read and last modified times of the given file.

QFileInfo fileinfo(filename);

The QFileInfo object is created.

QDateTime last_rea = fileinfo.lastRead();

The lastRead() method returns the date and time when the file was last read (accessed).

QDateTime last_mod = fileinfo.lastModified();

The lastModified() method returns the date and time when the file was last modified.

Output

$ ./file_times Makefile
Last read: Sun Nov 1 17:54:31 2015
Last modified: Sun Nov 1 17:54:30 2015

Working with directories


The QDir class has methods for working with directories.

dirs.cpp
#include <QTextStream>
#include <QDir>

int main(void) {
QTextStream out(stdout);
QDir dir;

if (dir.mkdir("mydir")) {
out << "mydir successfully created" << endl;
}

dir.mkdir("mydir2");

if (dir.exists("mydir2")) {
dir.rename("mydir2", "newdir");
}

dir.mkpath("temp/newdir");
}

In the example, we present four methods for working with directories.

if (dir.mkdir("mydir")) {
out << "mydir successfully created" << endl;
}

The mkdir() method creates a directory. It returns true if the directory was successfully created.

if (dir.exists("mydir2")) {
dir.rename("mydir2", "newdir");
}

The exists() checks for the existence of a directory. The rename() method renames the directory.

dir.mkpath("temp/newdir");

The mkpath() creates a new directory and all necessary parent directories in one shot.

Special paths
There are some special paths in the filesystem; for instance a home diretory or a root directory. The
QDir class is used to get the special paths in the system.

special_paths.cpp
#include <QTextStream>
#include <QDir>

int main(void) {

QTextStream out(stdout);

out << "Current path:" << QDir::currentPath() << endl;


out << "Home path:" << QDir::homePath() << endl;
out << "Temporary path:" << QDir::tempPath() << endl;
out << "Rooth path:" << QDir::rootPath() << endl;
}
The example prints four special paths.

out << "Current path:" << QDir::currentPath() << endl;

The current working directory is retrieved with the QDir::currentPath() method.

out << "Home path:" << QDir::homePath() << endl;

The home directory is returned with the QDir::homePath() method.

out << "Temporary path:" << QDir::tempPath() << endl;

The temporary directory is retrieved with the QDir::tempPath() method.

out << "Rooth path:" << QDir::rootPath() << endl;

The root directory is returned by the QDir::rootPath() method.

Output

$ ./special_paths
Current path:/home/janbodnar/prog/qt4/files/special_paths
Home path:/home/janbodnar
Temporary path:/tmp
Rooth path:/

File path
A file is identified by its name and path; a path consists of a file name, a base name, and a suffix.

file_path.cpp
#include <QTextStream>
#include <QFileInfo>

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

QTextStream out(stdout);

if (argc != 2) {

out << "Usage: file_times file" << endl;


return 1;
}

QString filename = argv[1];

QFileInfo fileinfo(filename);

QString absPath = fileinfo.absoluteFilePath();


QString baseName = fileinfo.baseName();
QString compBaseName = fileinfo.completeBaseName();
QString fileName = fileinfo.fileName();
QString suffix = fileinfo.suffix();
QString compSuffix = fileinfo.completeSuffix();

out << "Absolute file path: " << absPath << endl;
out << "Base name: " << baseName << endl;
out << "Complete base name: " << compBaseName << endl;
out << "File name: " << fileName << endl;
out << "Suffix: " << suffix << endl;
out << "Whole suffix: " << compSuffix << endl;
}

In the example, we use several methods to print the file path and its parts of the given file name.

QFileInfo fileinfo(filename);

The file path is identified using the QFileInfo class.

QString absPath = fileinfo.absoluteFilePath();

The absoluteFilePath() method returns an absolute path including the file name.

QString baseName = fileinfo.baseName();

The baseName() method returns the base name—the name of the file without the path.

QString compBaseName = fileinfo.completeBaseName();

The completeBaseName() method returns the complete base name—all characters in the file up to
(but not including) the last dot character.

QString fileName = fileinfo.fileName();

The fileName() method returns the file name, which is the base name and the extension.

QString suffix = fileinfo.suffix();

The suffix() method returns the file ending, which consists of all characters in the file after (but
not including) the last dot character.

QString compSuffix = fileinfo.completeSuffix();

A file ending may consist of several parts; the completeSuffix() method returns all characters in
the file after (but not including) the first dot character.

Output

$ ./file_path ~/Downloads/qt-everywhere-opensource-src-5.5.1.tar.gz
Absolute file path: /home/janbodnar/Downloads/qt-everywhere-opensource-src-5.5.1.tar.gz
Base name: qt-everywhere-opensource-src-5
Complete base name: qt-everywhere-opensource-src-5.5.1.tar
File name: qt-everywhere-opensource-src-5.5.1.tar.gz
Suffix: gz
Whole suffix: 5.1.tar.gz

Permissions
Files in the filesystem have a system of protection. Files are given flags which determine who can
access and modify them. The QFile::permissions() method returns an enumeration of OR-ed
flags for the file in question.

permissions.cpp
#include <QTextStream>
#include <QFile>

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

QTextStream out(stdout);

if (argc != 2) {

out << "Usage: permissions file" << endl;


return 1;
}

QString filename = argv[1];

QFile::Permissions ps = QFile::permissions(filename);

QString fper;

if (ps & QFile::ReadOwner) {


fper.append('r');
} else {
fper.append('-');
}

if (ps & QFile::WriteOwner) {


fper.append('w');
} else {
fper.append('-');
}

if (ps & QFile::ExeOwner) {


fper.append('x');
} else {
fper.append('-');
}

if (ps & QFile::ReadGroup) {


fper.append('r');
} else {
fper.append('-');
}
if (ps & QFile::WriteGroup) {
fper.append('w');
} else {
fper.append('-');
}

if (ps & QFile::ExeGroup) {


fper.append('x');
} else {
fper.append('-');
}

if (ps & QFile::ReadOther) {


fper.append('r');
} else {
fper.append('-');
}

if (ps & QFile::WriteOther) {


fper.append('w');
} else {
fper.append('-');
}

if (ps & QFile::ExeOther) {


fper.append('x');
} else {
fper.append('-');
}

out << fper << endl;


}

The example produces a Unix-like list of permissions for the given file. There are tree kinds of
possible users: owner, the group where the file belongs, and the rest of the users referred as others.
The first three positions belong to the owner of the file, the next three positions to the file's group,
and the last three characters belong to the others. There are four kinds of rights: reading (r),
writing or modifying (w), executing (x), and no rights (-).

QFile::Permissions ps = QFile::permissions(filename);

With the QFile::permissions() method, we get the enumeration of permission flags.

QString fper;

This string is dynamically built based on the given permissions.

if (ps & QFile::ReadOwner) {


fper.append('r');
} else {
fper.append('-');
}

We use the & operator to determine whether the returned enumeration consists of the
QFile::ReadOwner flag.

Output

$ ./permissions Makefile
rw-rw-r--

The owner and the group of users where the file belongs have the right to read the file and modify
it. Other users have the right to read the file. Since the file is not an executable, there are no rights
to execute the file.

Listing directory contents


In the following example, we display the contents of the given directory.

list_dir.cpp
#include <QTextStream>
#include <QFileInfo>
#include <QDir>

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

QTextStream out(stdout);

if (argc != 2) {

qWarning("Usage: list_dir directory");


return 1;
}

QString directory = argv[1];

QDir dir(directory);

if (!dir.exists()) {
qWarning("The directory does not exist");
return 1;
}

dir.setFilter(QDir::Files | QDir::AllDirs);
dir.setSorting(QDir::Size | QDir::Reversed);

QFileInfoList list = dir.entryInfoList();

int max_size = 0;

foreach (QFileInfo finfo, list) {

QString name = finfo.fileName();


int size = name.size();

if (size > max_size) {

max_size = size;
}
}

int len = max_size + 2;

out << QString("Filename").leftJustified(len).append("Bytes") << endl;

for (int i = 0; i < list.size(); ++i) {

QFileInfo fileInfo = list.at(i);


QString str = fileInfo.fileName().leftJustified(len);
str.append(QString("%1").arg(fileInfo.size()));
out << str << endl;
}

return 0;
}

To list the contents of a directory, we use the QDir class and its entryInfoList() method. The list of
the files is reversely sorted by its size and neatly lined up. There are two columns; the first column
contains file names and the second column file sizes.

QDir dir(directory);

A QDir object with the given directory name is created.

dir.setFilter(QDir::Files | QDir::AllDirs);

The setFilter() method specifies the kind of files that should be returned by the entryInfoList()
method.

dir.setSorting(QDir::Size | QDir::Reversed);

The setSorting() method specifies the sort order used by the entryInfoList() method.

QFileInfoList list = dir.entryInfoList();

The entryInfoList() method returns a list of QFileInfo objects for all the files and directories in
the directory, filtered and ordered by the filtering and ordering methods. QFileInfoList is a
synonym for QList<QFileInfo>.

foreach (QFileInfo finfo, list) {

QString name = finfo.fileName();


int size = name.size();

if (size > max_size) {

max_size = size;
}
}
We go through the list and determine the maximum file name size. This information is needed to
organize the output neatly.

int len = max_size + 2;

We give additional two spaces to the length of a column.

out << QString("Filename").leftJustified(len).append("Bytes") << endl;

Here we print the column names. The leftJustified() method returns a string of the given size,
whose string is left justified and padded by the fill character (defaults to space) to its right.

for (int i = 0; i < list.size(); ++i) {

QFileInfo fileInfo = list.at(i);


QString str = fileInfo.fileName().leftJustified(len);
str.append(QString("%1").arg(fileInfo.size()));
out << str << endl;
}

We go through the list of files and print their names and sizes. The first column is left justified and
padded with spaces as necessary; the second column is simply appended and the end of the line.

Output

$ ./list_dir .
Filename Bytes
list_dir.pro 291
list_dir.cpp 1092
.. 4096
. 4096
list_dir.o 10440
list_dir 19075
Makefile 28369

This is a sample output of the example.

In this chapter, we worked with files and directories.


First programs in Qt5
In this part of the Qt5 C++ programming tutorial, we create our first programs.

We display an application icon, a tooltip, and various mouse cursors. We center a window on the
screen and introduce the signal and slot mechanism.

Simple example
We start with a very simple example.

simple.cpp
#include <QApplication>
#include <QWidget>

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

QApplication app(argc, argv);

QWidget window;

window.resize(250, 150);
window.setWindowTitle("Simple example");
window.show();

return app.exec();
}

The example shows a basic window on the screen.

#include <QApplication>
#include <QWidget>

We include necessary header files.

QApplication app(argc, argv);

This is the application object. Each Qt5 application must create this object. (Except for console
applications.)
QWidget window;

This is our main widget.

window.resize(250, 150);
window.setWindowTitle("Simple example");
window.show();

Here we resize the widget and set a title for our main window. In this case, the QWidget is our main
window. And finally, we show the widget on the screen.

return app.exec();

The exec() method stars the main loop of the application.

Figure: Simple example

A tooltip

A tooltip is a specific hint about an item in an application. The following example will demonstrate,
how we can create a tooltip in Qt5 programming library.

tooltip.cpp
#include <QApplication>
#include <QWidget>

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

QApplication app(argc, argv);

QWidget window;

window.resize(250, 150);
window.move(300, 300);
window.setWindowTitle("ToolTip");
window.setToolTip("QWidget");
window.show();

return app.exec();
}
The example shows a tooltip for the main QWidget.

window.setWindowTitle("ToolTip");

We set a tooltip for the QWidget widget with the setToolTip() method.

Figure: A tooltip

The application icon

In the next example, we show the application icon. Most window managers display the icon in the
left corner of the titlebar and also on the taskbar.

icon.cpp
#include <QApplication>
#include <QWidget>
#include <QIcon>

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

QApplication app(argc, argv);

QWidget window;

window.resize(250, 150);
window.setWindowTitle("Icon");
window.setWindowIcon(QIcon("web.png"));
window.show();

return app.exec();
}

An icon is shown in the upper left corner of the window.

window.setWindowIcon(QIcon("web.png"));

To display an icon, we use the setWindowIcon() method and a QIcon class. The icon is a small PNG
file located in the current working directory.
Figure: Icon

Cursors
A cursor is a small icon that indicates the position of the mouse pointer. In the next example will
show various cursors that we can use in our programs.

cursors.cpp
#include <QApplication>
#include <QWidget>
#include <QFrame>
#include <QGridLayout>

class Cursors : public QWidget {

public:
Cursors(QWidget *parent = 0);
};

Cursors::Cursors(QWidget *parent)
: QWidget(parent) {

QFrame *frame1 = new QFrame(this);


frame1->setFrameStyle(QFrame::Box);
frame1->setCursor(Qt::SizeAllCursor);

QFrame *frame2 = new QFrame(this);


frame2->setFrameStyle(QFrame::Box);
frame2->setCursor(Qt::WaitCursor);

QFrame *frame3 = new QFrame(this);


frame3->setFrameStyle(QFrame::Box);
frame3->setCursor(Qt::PointingHandCursor);

QGridLayout *grid = new QGridLayout(this);


grid->addWidget(frame1, 0, 0);
grid->addWidget(frame2, 0, 1);
grid->addWidget(frame3, 0, 2);

setLayout(grid);
}

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

QApplication app(argc, argv);


Cursors window;

window.resize(350, 150);
window.setWindowTitle("Cursors");
window.show();

return app.exec();
}

In this example, we use three frames. Each of the frames has a different cursor set.

QFrame *frame1 = new QFrame(this);

A QFrame widget is created.

frame1->setFrameStyle(QFrame::Box);

We set a frame style with the setFrameStyle() method. This way we can see the boundaries of the
frames.

frame1->setCursor(Qt::SizeAllCursor);

A cursor is set to the frame with the setCursor() method.

QGridLayout *grid = new QGridLayout(this);


grid->addWidget(frame1, 0, 0);
grid->addWidget(frame2, 0, 1);
grid->addWidget(frame3, 0, 2);
setLayout(grid);

This will group all the frames into one row. We will talk more about this in the layout management
chapter.

QPushButton
In the next code example, we display a push button on the window. By clicking on the button we
close the application.

pushbutton.cpp
#include <QApplication>
#include <QWidget>
#include <QPushButton>

class MyButton : public QWidget {

public:
MyButton(QWidget *parent = 0);
};
MyButton::MyButton(QWidget *parent)
: QWidget(parent) {

QPushButton *quitBtn = new QPushButton("Quit", this);


quitBtn->setGeometry(50, 40, 75, 30);

connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);


}

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

QApplication app(argc, argv);

MyButton window;

window.resize(250, 150);
window.setWindowTitle("QPushButton");
window.show();

return app.exec();
}

In this code example, we use the concept of the signals and slots for the first time.

QPushButton *quitBtn = new QPushButton("Quit", this);


quitBtn->setGeometry(50, 40, 75, 30);

We create a new QPushButton. We manually resize it and place it on the window with the
setGeometry() window.

connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);

When we click on the button, a clicked signal is generated. A slot is the method which reacts to the
signal. In our case it is the quit slot of the main application object. The qApp is a global pointer to
the application object. It is defined in the QApplication header file.

Figure: QPushButton

Plus minus
We finish this section showing how widgets can communicate. The code is split into three files.

plusminus.h
#pragma once

#include <QWidget>
#include <QApplication>
#include <QPushButton>
#include <QLabel>

class PlusMinus : public QWidget {

Q_OBJECT

public:
PlusMinus(QWidget *parent = 0);

private slots:
void OnPlus();
void OnMinus();

private:
QLabel *lbl;

};

This is the header file of the example. In this file, we define two slots and a label widget.

class PlusMinus : public QWidget {

Q_OBJECT
...

The Q_OBJECT macro must be included in classes that declare their own signals and slots.

plusminus.cpp
#include "plusminus.h"
#include <QGridLayout>

PlusMinus::PlusMinus(QWidget *parent)
: QWidget(parent) {

QPushButton *plsBtn = new QPushButton("+", this);


QPushButton *minBtn = new QPushButton("-", this);
lbl = new QLabel("0", this);

QGridLayout *grid = new QGridLayout(this);


grid->addWidget(plsBtn, 0, 0);
grid->addWidget(minBtn, 0, 1);
grid->addWidget(lbl, 1, 1);

setLayout(grid);

connect(plsBtn, &QPushButton::clicked, this, &PlusMinus::OnPlus);


connect(minBtn, &QPushButton::clicked, this, &PlusMinus::OnMinus);
}

void PlusMinus::OnPlus() {
int val = lbl->text().toInt();
val++;
lbl->setText(QString::number(val));
}

void PlusMinus::OnMinus() {

int val = lbl->text().toInt();


val--;
lbl->setText(QString::number(val));
}

We have two push buttons and a label widget. We increase or decrease the number displayed by the
label with the buttons.

connect(plsBtn, &QPushButton::clicked, this, &PlusMinus::OnPlus);


connect(minBtn, &QPushButton::clicked, this, &PlusMinus::OnMinus);

Here we connect the clicked signals to their slots.

void PlusMinus::OnPlus() {

int val = lbl->text().toInt();


val++;
lbl->setText(QString::number(val));
}

In the OnPlus() method, we determine the current value of the label. The label widget displays a
string value, so we must convert it to the integer. We increase the number and set a new text for the
label. We convert a number to the string value.

main.cpp
#include "plusminus.h"

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

QApplication app(argc, argv);

PlusMinus window;

window.resize(300, 190);
window.setWindowTitle("Plus minus");
window.show();

return app.exec();
}

This is the main file of the code example.


Figure: Plus minus

In this chapter, we created our first programs in Qt5.


Menus and toolbars in Qt5
In this part of the Qt5 C++ programming tutorial, we will talk about menus and toolbars in Qt5
applications.

A menubar is a common part of a GUI application. It is a group of commands located in various


places called menus. Menus group commands that we can use in an application. Toolbars provide a
quick access to the most frequently used commands.

Simple menu

The first example shows a simple menu.

simplemenu.h
#pragma once

#include <QMainWindow>
#include <QApplication>

class SimpleMenu : public QMainWindow {

public:
SimpleMenu(QWidget *parent = 0);
};

This is a header file for our code example.

simplemenu.cpp
#include "simplemenu.h"
#include <QMenu>
#include <QMenuBar>

SimpleMenu::SimpleMenu(QWidget *parent)
: QMainWindow(parent) {

QAction *quit = new QAction("&Quit", this);

QMenu *file;
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, &QAction::triggered, qApp, QApplication::quit);
}

We have a menubar, a menu and an action. In order to work with menus, we must inherit from a
QMainWindow widget.

QAction *quit = new QAction("&Quit", this);

This code line creates a QAction. Each QMenu has one or more action objects.

QMenu *file;
file = menuBar()->addMenu("&File");

We create a QMenu object.

file->addAction(quit);

We put an action inside the menu using the addAction() method.

connect(quit, &QAction::triggered, qApp, QApplication::quit);

When we select this option from the menu, the application quits.

main.cpp
#include "simplemenu.h"

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

QApplication app(argc, argv);

SimpleMenu window;

window.resize(250, 150);
window.setWindowTitle("Simple menu");
window.show();

return app.exec();
}

The main file.


Figure: Simple menu

Icons, shortcuts, and separators


In the following example, we will further enhance our previous application. We add icons to the
menus, use shortcuts and a separator.

anothermenu.h
#pragma once

#include <QMainWindow>
#include <QApplication>

class AnotherMenu : public QMainWindow {

public:
AnotherMenu(QWidget *parent = 0);
};

The header file for the example.

anothermenu.cpp
#include "anothermenu.h"
#include <QMenu>
#include <QMenuBar>

AnotherMenu::AnotherMenu(QWidget *parent)
: QMainWindow(parent) {

QPixmap newpix("new.png");
QPixmap openpix("open.png");
QPixmap quitpix("quit.png");

QAction *newa = new QAction(newpix, "&New", this);


QAction *open = new QAction(openpix, "&Open", this);
QAction *quit = new QAction(quitpix, "&Quit", this);
quit->setShortcut(tr("CTRL+Q"));

QMenu *file;
file = menuBar()->addMenu("&File");
file->addAction(newa);
file->addAction(open);
file->addSeparator();
file->addAction(quit);
qApp->setAttribute(Qt::AA_DontShowIconsInMenus, false);

connect(quit, &QAction::triggered, qApp, &QApplication::quit);


}

In our example, we have one menu with three actions. Only the quit action will actually do
something if we select it. We also create a separator and a CTRL+Q shortcut, which terminates the
application.

QPixmap newpix("new.png");
QPixmap openpix("open.png");
QPixmap quitpix("quit.png");

These are images that we use in menus. Note that some desktop environments might not display
images in the menus.

QAction *newa = new QAction(newpix, "&New", this);


QAction *open = new QAction(openpix, "&Open", this);
QAction *quit = new QAction(quitpix, "&Quit", this);

In this code we use the QAction constructor with a pixmap as the first argument.

quit->setShortcut(tr("CTRL+Q"));

Here we create a keyboard shortcut. By pressing this shortcut, we will run the quit action which will
quit the application.

file->addSeparator();

We create a separator. The separator is a horizontal line which enables us to group menu actions
into some logical groups.

qApp->setAttribute(Qt::AA_DontShowIconsInMenus, false);

In some environments, the menu icons are not shown by default. In this case we can disable the
Qt::AA_DontShowIconsInMenus attribute.

main.cpp
#include "anothermenu.h"

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

QApplication app(argc, argv);

AnotherMenu window;

window.resize(350, 200);
window.setWindowTitle("Another menu");
window.show();
return app.exec();
}

This is the main file.

Figure: Another menu example

Checkable menu
In the next example, we create a checkable menu. This will be an action with a check box. The
option toggles the visibility of a statusbar.

checkable.h
#pragma once

#include <QMainWindow>
#include <QApplication>

class Checkable : public QMainWindow {

Q_OBJECT

public:
Checkable(QWidget *parent = 0);

private slots:
void toggleStatusbar();

private:
QAction *viewst;
};

The header file for the example.

checkable.cpp
#include "checkable.h"
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
Checkable::Checkable(QWidget *parent)
: QMainWindow(parent) {

viewst = new QAction("&View statusbar", this);


viewst->setCheckable(true);
viewst->setChecked(true);

QMenu *file;
file = menuBar()->addMenu("&File");
file->addAction(viewst);

statusBar();

connect(viewst, &QAction::triggered, this, &Checkable::toggleStatusbar);


}

void Checkable::toggleStatusbar() {

if (viewst->isChecked()) {

statusBar()->show();
} else {

statusBar()->hide();
}
}

A checkable menu item toggles the visibility of the statusbar.

viewst = new QAction("&View statusbar", this);


viewst->setCheckable(true);
viewst->setChecked(true);

We create an actiona and make it checkable with the setCheckable() method. The setChecked()
method makes it checked.

if (viewst->isChecked()) {

statusBar()->show();
} else {

statusBar()->hide();
}

Inside the toggleStatusbar() method, we determine if the menu item is checked and hide or show
the statusbar accordingly.

main.cpp
#include "checkable.h"

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


QApplication app(argc, argv);

Checkable window;

window.resize(250, 150);
window.setWindowTitle("Checkable menu");
window.show();

return app.exec();
}

This is the main file.

Figure: Checkable menu

QToolBar
The QToolBar class provides a movable panel that contains a set of controls which provide a quick
access to the application actions.

toolbar.h
#pragma once

#include <QMainWindow>
#include <QApplication>

class Toolbar : public QMainWindow {

Q_OBJECT

public:
Toolbar(QWidget *parent = 0);
};

The header file for the example.

toolbar.cpp
#include "toolbar.h"
#include <QToolBar>
#include <QIcon>
#include <QAction>

Toolbar::Toolbar(QWidget *parent)
: QMainWindow(parent) {

QPixmap newpix("new.png");
QPixmap openpix("open.png");
QPixmap quitpix("quit.png");

QToolBar *toolbar = addToolBar("main toolbar");


toolbar->addAction(QIcon(newpix), "New File");
toolbar->addAction(QIcon(openpix), "Open File");
toolbar->addSeparator();
QAction *quit = toolbar->addAction(QIcon(quitpix),
"Quit Application");

connect(quit, &QAction::triggered, qApp, &QApplication::quit);


}

To create a toolbar, we inherit from the QMainWindow widget.

QToolBar *toolbar = addToolBar("main toolbar");

The addToolBar() method creates a toolbar and returns a pointer to it.

toolbar->addAction(QIcon(newpix), "New File");


toolbar->addAction(QIcon(openpix), "Open File");
toolbar->addSeparator();

Here we add two actions and a separator to the toolbar.

main.cpp
#include "toolbar.h"

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

QApplication app(argc, argv);

Toolbar window;

window.resize(300, 200);
window.setWindowTitle("QToolBar");
window.show();

return app.exec();
}

This is the main file.


Figure: QToolBar

Application skeleton
In the end of this part of the C++ Qt5 tutorial, we create an application skeleton. The example is
based mainly on the QMainWindow widget.

skeleton.h
#pragma once

#include <QMainWindow>
#include <QApplication>

class Skeleton : public QMainWindow {

Q_OBJECT

public:
Skeleton(QWidget *parent = 0);
};

The header file for the example.

skeleton.cpp
#include "skeleton.h"
#include <QToolBar>
#include <QIcon>
#include <QAction>
#include <QMenu>
#include <QMenuBar>
#include <QStatusBar>
#include <QTextEdit>

Skeleton::Skeleton(QWidget *parent)
: QMainWindow(parent) {

QPixmap newpix("new.png");
QPixmap openpix("open.png");
QPixmap quitpix("quit.png");

QAction *quit = new QAction("&Quit", this);


QMenu *file;
file = menuBar()->addMenu("&File");
file->addAction(quit);

connect(quit, &QAction::triggered, qApp, &QApplication::quit);

QToolBar *toolbar = addToolBar("main toolbar");


toolbar->addAction(QIcon(newpix), "New File");
toolbar->addAction(QIcon(openpix), "Open File");
toolbar->addSeparator();

QAction *quit2 = toolbar->addAction(QIcon(quitpix),


"Quit Application");
connect(quit2, &QAction::triggered, qApp, &QApplication::quit);

QTextEdit *edit = new QTextEdit(this);

setCentralWidget(edit);

statusBar()->showMessage("Ready");
}

Here we create a menu a toolbar and a statusbar.

QTextEdit *edit = new QTextEdit(this);

setCentralWidget(edit);

We create a QTextEdit widget and place it into the central part of the QMainWindow widget.

main.cpp
#include "skeleton.h"

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

QApplication app(argc, argv);

Skeleton window;

window.resize(350, 250);
window.setWindowTitle("Application skeleton");
window.show();

return app.exec();
}

This is the main file.


Figure: Application skeleton

In this part of the Qt5 tutorial, we have covered menus and toolbars.
Layout management in Qt5
In this part of the Qt5 programming tutorial, we will talk about the layout management of widgets.
We mention QHBoxLayout, QVBoxLayout, QFormLayout, and QGridLayout managers.

A typical application consists of various widgets. Those widgets are placed inside layouts. A
programmer must manage the layout of the application. In Qt5 we have two options:

absolute positioning
layout managers

Absolute Positioning
The programmer specifies the position and the size of each widget in pixels. When we use absolute
positioning, we have to understand several things.

The size and the position of a widget do not change if we resize a window.
Applications look different (often poorly) on various platforms.
Changing fonts in our application might spoil the layout.
If we decide to change our layout, we must completely redo our layout, which is tedious and
time consuming.

There might be situations where we can possibly use absolute positioning. But mostly, in real world
programs, programmers use layout managers.

absolute.cpp
#include <QApplication>
#include <QDesktopWidget>
#include <QTextEdit>
class Absolute : public QWidget {

public:
Absolute(QWidget *parent = 0);
};

Absolute::Absolute(QWidget *parent)
: QWidget(parent) {

QTextEdit *ledit = new QTextEdit(this);


ledit->setGeometry(5, 5, 200, 150);
}

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

QApplication app(argc, argv);

Absolute window;

window.setWindowTitle("Absolute");
window.show();

return app.exec();
}

The setGeometry() method is used to position the widget on the window in absolute coordinates.

QTextEdit *edit = new QTextEdit(this);


ledit->setGeometry(5, 5, 200, 150);

We create a QTextEdit widget and manually position it. The setGeometry() method does two
things: it positions the widget to absolute coordinates and resizes the widget.

Figure: before resizement Figure: after resizement

QVBoxLayout
The QVBoxLayout class lines up widgets vertically. The widgets are added to the layout using the
addWidget() method.

verticalbox.h
#pragma once

#include <QWidget>

class VerticalBox : public QWidget {

public:
VerticalBox(QWidget *parent = 0);
};

The header file.

verticalbox.cpp
#include "verticalbox.h"
#include <QVBoxLayout>
#include <QPushButton>

VerticalBox::VerticalBox(QWidget *parent)
: QWidget(parent) {

QVBoxLayout *vbox = new QVBoxLayout(this);


vbox->setSpacing(1);

QPushButton *settings = new QPushButton("Settings", this);


settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *accounts = new QPushButton("Accounts", this);
accounts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *loans = new QPushButton("Loans", this);
loans->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *cash = new QPushButton("Cash", this);
cash->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QPushButton *debts = new QPushButton("Debts", this);
debts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

vbox->addWidget(settings);
vbox->addWidget(accounts);
vbox->addWidget(loans);
vbox->addWidget(cash);
vbox->addWidget(debts);

setLayout(vbox);
}

In our example, we have one vertical layout manager. We put five buttons into it. We make all
buttons expandable in both directions.

QVBoxLayout *vbox = new QVBoxLayout(this);


vbox->setSpacing(1);

We create the QVBoxLayout and set 1 px spacing among child widgets.

QPushButton *settings = new QPushButton("Settings", this);


settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
We create a button and set a size policy for it. The child widgets are managed by the layout
manager. By default, the button is expanded horizontally and has a fixed size vertically. If we want
to change it, we set a new size policy. In our case, the button is expandable into both directions.

vbox->addWidget(settings);
vbox->addWidget(accounts);
...

We add the child widgets to the layout manager with the addWidget() method.

setLayout(vbox);

We set the QVBoxLayout manager for the window.

main.cpp
#include "verticalbox.h"
#include <QApplication>

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

QApplication app(argc, argv);

VerticalBox window;

window.resize(240, 230);
window.setWindowTitle("VerticalBox");
window.show();

return app.exec();
}

The main file.

Figure: QVBoxLayout

Buttons
In the following example, we display two buttons on the client area of the window. They will be
positioned in the right bottom corner of the window.

buttons.h
#pragma once

#include <QWidget>
#include <QPushButton>

class Buttons : public QWidget {

public:
Buttons(QWidget *parent = 0);

private:
QPushButton *okBtn;
QPushButton *applyBtn;
};

Header file.

buttons.cpp
#include "buttons.h"
#include <QVBoxLayout>
#include <QHBoxLayout>

Buttons::Buttons(QWidget *parent)
: QWidget(parent) {

QVBoxLayout *vbox = new QVBoxLayout(this);


QHBoxLayout *hbox = new QHBoxLayout();

okBtn = new QPushButton("OK", this);


applyBtn = new QPushButton("Apply", this);

hbox->addWidget(okBtn, 1, Qt::AlignRight);
hbox->addWidget(applyBtn, 0);

vbox->addStretch(1);
vbox->addLayout(hbox);
}

Say we wanted to have two buttons in the right bottom corner of the window.

QVBoxLayout *vbox = new QVBoxLayout(this);


QHBoxLayout *hbox = new QHBoxLayout();

We create two box layout managers: one vertical and one horizontal box layout manager.

okBtn = new QPushButton("OK", this);


applyBtn = new QPushButton("Apply", this);
We create two push buttons.

hbox->addWidget(okBtn, 1, Qt::AlignRight);
hbox->addWidget(applyBtn, 0);

The buttons are placed inside the horizontal layout manager. with the addWidget() method. These
buttons are right aligned. The first parameter is the child widget. The second parameter is the
stretch factor, and the last parameter is alignment. By setting the stretch factor to 1 for the OK
button, we give it space from the left side to the right side of the window. The widget does not
expand to all space alloted to it. Finally, the Qt::AlignRight constant aligns the widget to the right
of the allotted space.

vbox->addStretch(1);
vbox->addLayout(hbox);

We put an empty, expandable space into the vertical box by calling the addStretch() method. Then
we add the horizontal box layout to the vertical box layout.

main.cpp
#include <QApplication>
#include "buttons.h"

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

QApplication app(argc, argv);

Buttons window;

window.resize(290, 170);
window.setWindowTitle("Buttons");
window.show();

return app.exec();
}

The main file.

Figure: Buttons

Nesting layouts
The idea of the following example is to show that layout managers can be combined. By
combination of even simple layouts we can create sophisticated dialogs or windows. To nest
layouts, we utilize the addLayout() method.

nesting.h
#pragma once

#include <QWidget>

class Layouts : public QWidget {

public:
Layouts(QWidget *parent = 0);
};

This is the header file.

nesting.cpp
#include <QVBoxLayout>
#include <QPushButton>
#include <QListWidget>
#include "nesting.h"

Layouts::Layouts(QWidget *parent)
: QWidget(parent) {

QVBoxLayout *vbox = new QVBoxLayout();


QHBoxLayout *hbox = new QHBoxLayout(this);

QListWidget *lw = new QListWidget(this);


lw->addItem("The Omen");
lw->addItem("The Exorcist");
lw->addItem("Notes on a scandal");
lw->addItem("Fargo");
lw->addItem("Capote");

QPushButton *add = new QPushButton("Add", this);


QPushButton *rename = new QPushButton("Rename", this);
QPushButton *remove = new QPushButton("Remove", this);
QPushButton *removeall = new QPushButton("Remove All", this);

vbox->setSpacing(3);
vbox->addStretch(1);
vbox->addWidget(add);
vbox->addWidget(rename);
vbox->addWidget(remove);
vbox->addWidget(removeall);
vbox->addStretch(1);

hbox->addWidget(lw);
hbox->addSpacing(15);
hbox->addLayout(vbox);
setLayout(hbox);
}

In the example, we create a window that consists of four buttons and one list widget. The buttons
are grouped in a vertical column and placed to the right of the list widget. If we resize the window,
the list widget is being resized as well.

QVBoxLayout *vbox = new QVBoxLayout();

The QVBoxLayout will be the column for the buttons.

QHBoxLayout *hbox = new QHBoxLayout(this);

The QHBoxLayout will be the base layout for the widgets.

QListWidget *lw = new QListWidget(this);


lw->addItem("The Omen");
lw->addItem("The Exorcist");
lw->addItem("Notes on a scandal");
lw->addItem("Fargo");
lw->addItem("Capote");

The QListWidget is created.

QPushButton *add = new QPushButton("Add", this);


QPushButton *rename = new QPushButton("Rename", this);
QPushButton *remove = new QPushButton("Remove", this);
QPushButton *removeall = new QPushButton("Remove All", this);

Here we create our four buttons.

vbox->setSpacing(3);
vbox->addStretch(1);
vbox->addWidget(add);
vbox->addWidget(rename);
vbox->addWidget(remove);
vbox->addWidget(removeall);
vbox->addStretch(1);

The vertical box with four buttons is created. We put some little space among our buttons. Notice
that we add a stretch factor to the top and to the bottom of the vertical box. This way the buttons
are vertically centered.

hbox->addWidget(lw);
hbox->addSpacing(15);
hbox->addLayout(vbox);

The list widget and the vertical box of buttons are placed into the horizontal box layout. The
addLayout() method is used to add a layout to another layout.
setLayout(hbox);

We set the base layout for the parent window.

main.cpp
#include <QApplication>
#include "nesting.h"

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

QApplication app(argc, argv);

Layouts window;

window.setWindowTitle("Layouts");
window.show();

return app.exec();
}

This is the main file.

Figure: Nesting layouts

QFormLayout
QFormLayout is a simple layout manager that manages forms of input widgets and their associated

labels. It lays out its children in a two-column form. The left column consists of labels and the right
column consists of input widgets like QLineEdit or QSpinBox.

form.h
#pragma once

#include <QWidget>

class FormEx : public QWidget {

public:
FormEx(QWidget *parent = 0);
};

This is the header filer.

form.cpp
#include <QFormLayout>
#include <QLabel>
#include <QLineEdit>
#include "form.h"

FormEx::FormEx(QWidget *parent)
: QWidget(parent) {

QLineEdit *nameEdit = new QLineEdit(this);


QLineEdit *addrEdit = new QLineEdit(this);
QLineEdit *occpEdit = new QLineEdit(this);

QFormLayout *formLayout = new QFormLayout;


formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);
formLayout->addRow("Name:", nameEdit);
formLayout->addRow("Email:", addrEdit);
formLayout->addRow("Age:", occpEdit);

setLayout(formLayout);
}

The example creates a form consisting of three labels and three line edits.

QFormLayout *formLayout = new QFormLayout;

An instance of the QFormLayout is created.

formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter);

With the setLabelAlignment() metho, we set the alignment of the label widgets.

formLayout->addRow("Name:", nameEdit);

The addRow() method adds a new row to the bottom of the form layout, with the given label and
input widget.

main.cpp
#include <QApplication>
#include "form.h"

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

QApplication app(argc, argv);

FormEx window;
window.setWindowTitle("Form example");
window.show();

return app.exec();
}

This is the main file.

Figure: Simple form

QGridLayout
QGridLayout places its widgets in a grid. It is a powerful layout manager.

calculator.h
#pragma once

#include <QWidget>

class Calculator : public QWidget {

public:
Calculator(QWidget *parent = 0);

};

Header file.

calculator.cpp
#include <QGridLayout>
#include <QPushButton>
#include "calculator.h"

Calculator::Calculator(QWidget *parent)
: QWidget(parent) {

QGridLayout *grid = new QGridLayout(this);


grid->setSpacing(2);

QList<QString> values({ "7", "8", "9", "/",


"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
});
int pos = 0;

for (int i=0; i<4; i++) {


for (int j=0; j<4; j++) {

QPushButton *btn = new QPushButton(values[pos], this);


btn->setFixedSize(40, 40);
grid->addWidget(btn, i, j);
pos++;
}
}

setLayout(grid);
}

We create a skeleton of a calculator.

QGridLayout *grid = new QGridLayout(this);


grid->setSpacing(2);

We create the grid layout and set 2 px space among child widgets.

QList<QString> values({ "7", "8", "9", "/",


"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
});

These are the characters that are displayed on the buttons.

for (int i=0; i<4; i++) {


for (int j=0; j<4; j++) {

QPushButton *btn = new QPushButton(values[pos], this);


btn->setFixedSize(40, 40);
grid->addWidget(btn, i, j);
pos++;
}
}

We place sixteen widgets into the grid layout. Each of the buttons will have a fixed size.

main.cpp
#include <QApplication>
#include "calculator.h"

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

QApplication app(argc, argv);

Calculator window;

window.move(300, 300);
window.setWindowTitle("Calculator");
window.show();

return app.exec();
}

This is the main file.

Figure: QGridLayout

Review
In the next example of this chapter, we create a more complicated window using the QGridLayout
manager.

review.h
#pragma once

#include <QWidget>

class Review : public QWidget {

public:
Review(QWidget *parent = 0);
};

Header file.

review.cpp
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include "review.h"

Review::Review(QWidget *parent)
: QWidget(parent) {

QGridLayout *grid = new QGridLayout(this);


grid->setVerticalSpacing(15);
grid->setHorizontalSpacing(10);
QLabel *title = new QLabel("Title:", this);
grid->addWidget(title, 0, 0, 1, 1);
title->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

QLineEdit *edt1 = new QLineEdit(this);


grid->addWidget(edt1, 0, 1, 1, 1);

QLabel *author = new QLabel("Author:", this);


grid->addWidget(author, 1, 0, 1, 1);
author->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

QLineEdit *edt2 = new QLineEdit(this);


grid->addWidget(edt2, 1, 1, 1, 1);

QLabel *review = new QLabel("Review:", this);


grid->addWidget(review, 2, 0, 1, 1);
review->setAlignment(Qt::AlignRight | Qt::AlignTop);

QTextEdit *te = new QTextEdit(this);


grid->addWidget(te, 2, 1, 3, 1);

setLayout(grid);
}

The code creates a window which could be used to enter an author, title, and a review for a book.

QGridLayout *grid = new QGridLayout(this);

The QGridLayout manager is created.

grid->setVerticalSpacing(15);
grid->setHorizontalSpacing(10);

We add vertical spacing with the setVerticalSpacing() method and horizontal spacing with the
setHorizontalSpacing() method.

QLabel *title = new QLabel("Title", this);


grid->addWidget(title, 0, 0, 1, 1);

These code lines create a label widget and place it into the grid layout. The addWidget() method has
five parameters. The first parameter is the child widget, a label in our case. The next two
parameters are the row and column in the grid where we place the label. Finally, the last
parameters are the rowspan and the colspan. These parameters specify how many rows the current
widget will span. In our case, the label will span only one column and one row.

title->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

The setAlignment() method aligns the title label in its cell. Horizontally, it is right aligned.
Vertically, it is centered.

QTextEdit *te = new QTextEdit(this);


grid->addWidget(te, 2, 1, 3, 1);

The QTextEdit widget is placed into the third row and second column; it spans three rows and one
column.

main.cpp
#include <QApplication>
#include "review.h"

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

QApplication app(argc, argv);

Review window;

window.setWindowTitle("Review");
window.show();

return app.exec();
}

Main file.

Figure: Review

This part of the Qt5 tutorial was dedicated to layout management.


Events and signals in Qt5
In this part of the Qt5 C++ programming tutorial we talk about events and signals.

Events are an important part in any GUI program. All GUI applications are event-driven. An
application reacts to different event types which are generated during its life. Events are generated
mainly by the user of an application. But they can be generated by other means as well, e.g. Internet
connection, window manager, or a timer. In the event model, there are three participants:

event source
event object
event target

The event source is the object whose state changes. It generates Events. The event object (Event)
encapsulates the state changes in the event source. The event target is the object that wants to be
notified. Event source object delegates the task of handling an event to the event target.

When we call the application's exec() method, the application enters the main loop. The main loop
fetches events and sends them to the objects. Qt has a unique signal and slot mechanism. This
signal and slot mechanism is an extension to the C++ programming language.

Signals and slots are used for communication between objects. A signal is emitted when a
particular event occurs. A slot is a normal C++ method; it is called when a signal connected to it is
emitted.

Click
The first example shows a very simple event handling example. We have one push button. By
clicking on the push button, we terminate the application.

click.h
#pragma once

#include <QWidget>

class Click : public QWidget {


public:
Click(QWidget *parent = 0);
};

This is the header file.

click.cpp
#include <QPushButton>
#include <QApplication>
#include <QHBoxLayout>
#include "click.h"

Click::Click(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);


hbox->setSpacing(5);

QPushButton *quitBtn = new QPushButton("Quit", this);


hbox->addWidget(quitBtn, 0, Qt::AlignLeft | Qt::AlignTop);

connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);


}

We display a QPushButton on the window.

connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);

The connect() method connects a signal to the slot. When we click on the Quit button, the clicked
signal is generated. The qApp is a global pointer to the application object. It is defined in the
<QApplication> header file. The quit() method is called when the clicked signal is emitted.

main.cpp
#include <QApplication>
#include "click.h"

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

QApplication app(argc, argv);

Click window;

window.resize(250, 150);
window.setWindowTitle("Click");
window.show();

return app.exec();
}

This is the main file.

Figure: Click
KeyPress
In the following example, we react to a key press.

keypress.h
#pragma once

#include <QWidget>

class KeyPress : public QWidget {

public:
KeyPress(QWidget *parent = 0);

protected:
void keyPressEvent(QKeyEvent * e);
};

This is the keypress.h header file.

keypress.cpp
#include <QApplication>
#include <QKeyEvent>
#include "keypress.h"

KeyPress::KeyPress(QWidget *parent)
: QWidget(parent)
{ }

void KeyPress::keyPressEvent(QKeyEvent *event) {

if (event->key() == Qt::Key_Escape) {
qApp->quit();
}
}

The application terminates if we press the Escape key.

void KeyPress::keyPressEvent(QKeyEvent *e) {

if (e->key() == Qt::Key_Escape) {
qApp->quit();
}
}

One of the ways of working with events in Qt5 is to reimplement an event handler. The QKeyEvent is
an event object, which holds information about what has happened. In our case, we use the event
object to determine which key was actually pressed.

main.cpp
#include <QApplication>
#include "keypress.h"

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

QApplication app(argc, argv);

KeyPress window;

window.resize(250, 150);
window.setWindowTitle("Key press");
window.show();

return app.exec();
}

This is the main file.

QMoveEvent

The QMoveEvent class contains event parameters for move events. Move events are sent to widgets
that have been moved.

move.h
#pragma once

#include <QMainWindow>

class Move : public QWidget {

Q_OBJECT

public:
Move(QWidget *parent = 0);

protected:
void moveEvent(QMoveEvent *e);
};

This is the move.h header file.

move.cpp
#include <QMoveEvent>
#include "move.h"

Move::Move(QWidget *parent)
: QWidget(parent)
{ }

void Move::moveEvent(QMoveEvent *e) {

int x = e->pos().x();
int y = e->pos().y();

QString text = QString::number(x) + "," + QString::number(y);

setWindowTitle(text);
}

In our code programming example, we react to a move event. We determine the current x, y
coordinates of the upper left corner of the client area of the window and set those values to the title
of the window.

int x = e->pos().x();
int y = e->pos().y();

We use the QMoveEvent object to determine the x, y values.

QString text = QString::number(x) + "," + QString::number(y);

We convert the integer values to strings.

setWindowTitle(text);

The setWindowTitle() method sets the text to the title of the window.

main.cpp
#include <QApplication>
#include "move.h"

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

QApplication app(argc, argv);

Move window;

window.resize(250, 150);
window.setWindowTitle("Move");
window.show();

return app.exec();
}

This is the main file.


Figure: QMoveEvent

Disconnecting a signal
A signal can be disconnected from the slot. The next example shows how we can accomplish this.

disconnect.h
#pragma once

#include <QWidget>
#include <QPushButton>

class Disconnect : public QWidget {

Q_OBJECT

public:
Disconnect(QWidget *parent = 0);

private slots:
void onClick();
void onCheck(int);

private:
QPushButton *clickBtn;
};

In the header file, we have declared two slots. The slots is not a C++ keyword, it is a Qt5 extension.
These extensions are handled by the preprocessor, before the code is compiled. When we use
signals and slots in our classes, we must provide a Q_OBJECT macro at the beginnig of the class
definition. Otherwise, the preprocessor would complain.

disconnect.cpp
#include <QTextStream>
#include <QCheckBox>
#include <QHBoxLayout>
#include "disconnect.h"

Disconnect::Disconnect(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);


hbox->setSpacing(5);
clickBtn = new QPushButton("Click", this);
hbox->addWidget(clickBtn, 0, Qt::AlignLeft | Qt::AlignTop);

QCheckBox *cb = new QCheckBox("Connect", this);


cb->setCheckState(Qt::Checked);
hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);

connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);


connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck);
}

void Disconnect::onClick() {

QTextStream out(stdout);
out << "Button clicked" << endl;
}

void Disconnect::onCheck(int state) {

if (state == Qt::Checked) {
connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
} else {
disconnect(clickBtn, &QPushButton::clicked, this,
&Disconnect::onClick);
}
}

In our example, we have a button and a check box. The check box connects and disconnects a slot
from the buttons clicked signal. This example must be executed from the command line.

connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);


connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck);

Here we connect signals to our user defined slots.

void Disconnect::onClick() {

QTextStream out(stdout);
out << "Button clicked" << endl;
}

If we click on the Click button, we send the "Button clicked" text to the terminal window.

void Disconnect::onCheck(int state) {

if (state == Qt::Checked) {
connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
} else {
disconnect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
}
}

Inside the onCheck() slot, we connect or disconnect the onClick() slot from the Click button,
depending on the received state.

main.cpp
#include <QApplication>
#include "disconnect.h"

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

QApplication app(argc, argv);

Disconnect window;

window.resize(250, 150);
window.setWindowTitle("Disconnect");
window.show();

return app.exec();
}

This is the main file.

Timer

A timer is used to implement single shot or repetitive tasks. A good example where we use a timer
is a clock; each second we must update our label displaying the current time.

timer.h
#pragma once

#include <QWidget>
#include <QLabel>

class Timer : public QWidget {

public:
Timer(QWidget *parent = 0);

protected:
void timerEvent(QTimerEvent *e);

private:
QLabel *label;
};

This is the header file.

timer.cpp
#include "timer.h"
#include <QHBoxLayout>
#include <QTime>

Timer::Timer(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);


hbox->setSpacing(5);

label = new QLabel("", this);


hbox->addWidget(label, 0, Qt::AlignLeft | Qt::AlignTop);

QTime qtime = QTime::currentTime();


QString stime = qtime.toString();
label->setText(stime);

startTimer(1000);
}

void Timer::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

QTime qtime = QTime::currentTime();


QString stime = qtime.toString();
label->setText(stime);
}

In our example, we display a current local time on the window.

label = new QLabel("", this);

To display a time, we use a label widget.

QTime qtime = QTime::currentTime();


QString stime = qtime.toString();
label->setText(stime);

Here we determine the current local time. We set it to the label widget.

startTimer(1000);

We start the timer. Every 1000 ms a timer event is generated.

void Timer::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

QTime qtime = QTime::currentTime();


QString stime = qtime.toString();
label->setText(stime);
}

To work with timer events, we must reimplement the timerEvent() method.

main.cpp
#include <QApplication>
#include "timer.h"

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

QApplication app(argc, argv);

Timer window;

window.resize(250, 150);
window.setWindowTitle("Timer");
window.show();

return app.exec();
}

This is the main file.

Figure: Timer

This chapter was dedicated to events and signals in Qt5.


Qt5 Widgets
In this part of the Qt5 C++ programming tutorial, we will talk about some basic Qt5 widgets. We
have examples for the QLabel, QSlider, QComboBox, QSpinBox, QLineEdit, and QMainWindow widgets.

Widgets are basic building blocks of a GUI application. Qt5 library has a rich set of various widgets.

QLabel
QLabel is used to display text and image. No user interaction is available. The following example

displays text.

label.h
#pragma once

#include <QWidget>
#include <QLabel>

class Label : public QWidget {

public:
Label(QWidget *parent = 0);

private:
QLabel *label;
};

This is a header file for our code example.

label.cpp
#include <QVBoxLayout>
#include <QFont>
#include "label.h"

Label::Label(QWidget *parent)
: QWidget(parent) {

QString lyrics = "Who doesn't long for someone to hold\n\


Who knows how to love you without being told\n\
Somebody tell me why I'm on my own\n\
If there's a soulmate for everyone\n\
\n\
Here we are again, circles never end\n\
How do I find the perfect fit\n\
There's enough for everyone\n\
But I'm still waiting in line\n\
\n\
Who doesn't long for someone to hold\n\
Who knows how to love you without being told\n\
Somebody tell me why I'm on my own\n\
If there's a soulmate for everyone";

label = new QLabel(lyrics, this);


label->setFont(QFont("Purisa", 10));

QVBoxLayout *vbox = new QVBoxLayout();


vbox->addWidget(label);
setLayout(vbox);
}

We use QLabel widget to display lyrics in a window.

label = new QLabel(lyrics, this);


label->setFont(QFont("Purisa", 10));

We create a label widget and set a specific font for it.

main.cpp
#include <QApplication>
#include <QTextStream>
#include "label.h"

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

QApplication app(argc, argv);

Label window;

window.setWindowTitle("QLabel");
window.show();

return app.exec();
}

This is the main file.


Figure: QLabel

QSlider

QSlider is a widget that has a simple handle. This handle can be pulled back and forth. This way we

are choosing a value for a specific task.

slider.h
#pragma once

#include <QWidget>
#include <QSlider>
#include <QLabel>

class Slider : public QWidget {

Q_OBJECT

public:
Slider(QWidget *parent = 0);

private:
QSlider *slider;
QLabel *label;
};

The header file for the example.

slider.cpp
#include <QHBoxLayout>
#include "slider.h"

Slider::Slider(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);

slider = new QSlider(Qt::Horizontal , this);


hbox->addWidget(slider);

label = new QLabel("0", this);


hbox->addWidget(label);

connect(slider, &QSlider::valueChanged, label,


static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
}

We display two widgets: a slider and a label. The slider controls the number displayed in the label.

slider = new QSlider(Qt::Horizontal , this);

A horizontal QSlider is created.

connect(slider, &QSlider::valueChanged, label,


static_cast<void (QLabel::*)(int)>(&QLabel::setNum));

In this code line, we connect the valueChanged() signal to the label's built-in setNum() slot. Since
the setNum() method is overloaded, we use a static_cast to choose the correct method.

main.cpp
#include <QApplication>
#include "slider.h"

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

QApplication app(argc, argv);

Slider window;

window.setWindowTitle("QSlider");
window.show();

return app.exec();
}

This is the main file.

Figure: QSlider

QComboBox
QComboBox is a widget which presents a list of options to the user in a way that takes up the

minimum amount of screen space. It is a selection widget that displays the current item, and can
pop up a list of selectable items. A combobox may be editable, allowing the user to modify each
item in the list.

combobox.h
#pragma once

#include <QWidget>
#include <QComboBox>
#include <QLabel>

class ComboBoxEx : public QWidget {

Q_OBJECT

public:
ComboBoxEx(QWidget *parent = 0);

private:
QComboBox *combo;
QLabel *label;
};

We work with two widgets: a combo box and a label.

combobox.cpp
#include <QHBoxLayout>
#include "combobox.h"

ComboBoxEx::ComboBoxEx(QWidget *parent)
: QWidget(parent) {

QStringList distros = {"Arch", "Xubuntu", "Redhat", "Debian",


"Mandriva"};

QHBoxLayout *hbox = new QHBoxLayout(this);

combo = new QComboBox();


combo->addItems(distros);

hbox->addWidget(combo);
hbox->addSpacing(15);

label = new QLabel("Arch", this);


hbox->addWidget(label);

connect(combo, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated),


label, &QLabel::setText);
}

In the example, a selected item from the combo box is shown in the label.
QStringList distros = {"Arch", "Xubuntu", "Redhat", "Debian",
"Mandriva"};

A QStringList stores the data of the combo box. We have a list of Linux distributions.

combo = new QComboBox();


combo->addItems(distros);

A QComboBox is created and the items are inserted with the addItems() method.

connect(combo, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated),


label, &QLabel::setText);

The activated() signal of the combo box is plugged to the label's setText() slot. Since the signal is
overloaded, we do a static cast.

main.cpp
#include <QApplication>
#include "combobox.h"

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

QApplication app(argc, argv);

ComboBoxEx window;

window.resize(300, 150);
window.setWindowTitle("QComboBox");
window.show();

return app.exec();
}

This is the main file of the application.

Figure: QComboBox

QSpinBox
QSpinbox is a widget that is used to handle integers and discrete sets of values. In our code example,
we will have one spinbox widget. We can choose numbers 0..99. The currently chosen value is
displayed in a label widget.

spinbox.h
#pragma once

#include <QWidget>
#include <QSpinBox>

class SpinBox : public QWidget {

Q_OBJECT

public:
SpinBox(QWidget *parent = 0);

private:
QSpinBox *spinbox;
};

This is the header file for the spinbox example.

spinbox.cpp
#include <QHBoxLayout>
#include <QLabel>
#include "spinbox.h"

SpinBox::SpinBox(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);


hbox->setSpacing(15);

spinbox = new QSpinBox(this);


QLabel *lbl = new QLabel("0", this);

hbox->addWidget(spinbox);
hbox->addWidget(lbl);

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),


lbl, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));
}

We place a spinbox on the window and connect its valueChanged() signal to the QLabel's setNum()
slot.

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),


lbl, static_cast<void (QLabel::*)(int)>(&QLabel::setNum));

We need to do casting twice because both the signal and the slot are overloaded.

main.cpp
#include <QApplication>
#include "spinbox.h"

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

QApplication app(argc, argv);

SpinBox window;

window.resize(250, 150);
window.setWindowTitle("QSpinBox");
window.show();

return app.exec();
}

This is the main file.

Figure: QSpinBox

QLineEdit

QLineEdit is a widget that allows to enter and edit a single line of plain text. There are undo/redo,

cut/paste and drag & drop functions available for QLineEdit widget.

In our example, we show three labels and three line edits.

ledit.h
#pragma once

#include <QWidget>

class Ledit : public QWidget {

public:
Ledit(QWidget *parent = 0);
};

The header file for the example.

ledit.cpp
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include "ledit.h"

Ledit::Ledit(QWidget *parent)
: QWidget(parent) {

QLabel *name = new QLabel("Name:", this);


name->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
QLabel *age = new QLabel("Age:", this);
age->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
QLabel *occupation = new QLabel("Occupation:", this);
occupation->setAlignment(Qt::AlignRight | Qt::AlignVCenter);

QLineEdit *le1 = new QLineEdit(this);


QLineEdit *le2 = new QLineEdit(this);
QLineEdit *le3 = new QLineEdit(this);

QGridLayout *grid = new QGridLayout();

grid->addWidget(name, 0, 0);
grid->addWidget(le1, 0, 1);
grid->addWidget(age, 1, 0);
grid->addWidget(le2, 1, 1);
grid->addWidget(occupation, 2, 0);
grid->addWidget(le3, 2, 1);

setLayout(grid);
}

We display three labels and three line edits. These widgets are organized with the QGridLayout
manager.

main.cpp
#include "ledit.h"
#include <QApplication>

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

QApplication app(argc, argv);

Ledit window;

window.setWindowTitle("QLineEdit");
window.show();

return app.exec();
}

This is the main file.

Figure: QLineEdit

Statusbar
A statusbar is a panel that is used to display status information about the application.
In our example, we have two buttons and a statusbar. Each of the buttons shows a message if we
click on them. The statusbar widget is part of the QMainWindow widget.

statusbar.h
#pragma once

#include <QMainWindow>
#include <QPushButton>

class Statusbar : public QMainWindow {

Q_OBJECT

public:
Statusbar(QWidget *parent = 0);

private slots:
void OnOkPressed();
void OnApplyPressed();

private:
QPushButton *okBtn;
QPushButton *aplBtn;
};

The header file for the example.

statusbar.cpp
#include <QLabel>
#include <QFrame>
#include <QStatusBar>
#include <QHBoxLayout>
#include "statusbar.h"

Statusbar::Statusbar(QWidget *parent)
: QMainWindow(parent) {

QFrame *frame = new QFrame(this);


setCentralWidget(frame);

QHBoxLayout *hbox = new QHBoxLayout(frame);

okBtn = new QPushButton("OK", frame);


hbox->addWidget(okBtn, 0, Qt::AlignLeft | Qt::AlignTop);

aplBtn = new QPushButton("Apply", frame);


hbox->addWidget(aplBtn, 1, Qt::AlignLeft | Qt::AlignTop);

statusBar();

connect(okBtn, &QPushButton::clicked, this, &Statusbar::OnOkPressed);


connect(aplBtn, &QPushButton::clicked, this, &Statusbar::OnApplyPressed);
}
void Statusbar::OnOkPressed() {

statusBar()->showMessage("OK button pressed", 2000);


}

void Statusbar::OnApplyPressed() {

statusBar()->showMessage("Apply button pressed", 2000);


}

This is the statusbar.cpp file.

QFrame *frame = new QFrame(this);


setCentralWidget(frame);

The QFrame widget is put into the center area of the QMainWindow widget. The central area can take
only one widget.

okBtn = new QPushButton("OK", frame);


hbox->addWidget(okBtn, 0, Qt::AlignLeft | Qt::AlignTop);

aplBtn = new QPushButton("Apply", frame);


hbox->addWidget(aplBtn, 1, Qt::AlignLeft | Qt::AlignTop);

We create two QPushButton widgets and place them into a horizontal box. The parent of the buttons
is the frame widget.

statusBar();

To display a statusbar widget, we call the statusBar() method of the QMainWindow widget.

void Statusbar::OnOkPressed() {

statusBar()->showMessage("OK button pressed", 2000);


}

The showMessage() method shows the message on the statusbar. The last parameter specifies the
number of milliseconds that the message is displayed on the statusbar.

main.cpp
#include <QApplication>
#include "statusbar.h"

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

QApplication app(argc, argv);

Statusbar window;

window.resize(300, 200);
window.setWindowTitle("QStatusBar");
window.show();

return app.exec();
}

This is the main file.

Figure: Statusbar example

In this part of the Qt5 tutorial, we have introduced several Qt5 widgets.
Qt5 Widgets II
In this part of the Qt5 C++ programming tutorial, we will continue talking about the Qt5 widgets.
We cover the following widgets: QCheckBox, QListWidget, QProgressBar, QPixmap, QSplitter, and
QTableWidget.

QCheckBox
The QCheckBox is a widget that has two states: on and off. It is a box with a label. If the checkbox is
checked, it is represented by a tick in a box.

In our example, we display a checkbox on the window. If the checkbox is checked, the title of the
window is displayed. Otherwise it is hidden.

checkbox.h
#pragma once

#include <QWidget>

class CheckBox : public QWidget {

Q_OBJECT

public:
CheckBox(QWidget *parent = 0);

private slots:
void showTitle(int);
};

This is a header file for our code example.

checkbox.cpp
#include <QCheckBox>
#include <QHBoxLayout>
#include "checkbox.h"

CheckBox::CheckBox(QWidget *parent)
: QWidget(parent) {
QHBoxLayout *hbox = new QHBoxLayout(this);

QCheckBox *cb = new QCheckBox("Show Title", this);


cb->setCheckState(Qt::Checked);
hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);

connect(cb, &QCheckBox::stateChanged, this, &CheckBox::showTitle);


}

void CheckBox::showTitle(int state) {

if (state == Qt::Checked) {
setWindowTitle("QCheckBox");
} else {
setWindowTitle(" ");
}
}

We display a checkbox on the window and connect it to the showTitle() slot.

cb->setCheckState(Qt::Checked);

The checkbox is checked when the example starts.

void CheckBox::showTitle(int state) {

if (state == Qt::Checked) {
setWindowTitle("QCheckBox");
} else {
setWindowTitle(" ");
}
}

We determine the state of the check box and call the setWindowTitle() accordingly.

main.cpp
#include <QApplication>
#include "checkbox.h"

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

QApplication app(argc, argv);

CheckBox window;

window.resize(250, 150);
window.setWindowTitle("QCheckBox");
window.show();

return app.exec();
}

This is the main file.


Figure: QCheckBox

QListWidget
A QListWidget is a widget that is used to display a list of items. In our example, we will demonstrate
how to add, rename, and remove items from the list widget.

listwidget.h
#pragma once

#include <QWidget>
#include <QPushButton>
#include <QListWidget>

class ListWidget : public QWidget {

Q_OBJECT

public:
ListWidget(QWidget *parent = 0);

private slots:
void addItem();
void renameItem();
void removeItem();
void clearItems();

private:
QListWidget *lw;
QPushButton *add;
QPushButton *rename;
QPushButton *remove;
QPushButton *removeAll;
};

The header file for the example.

listwidget.cpp
#include "listwidget.h"
#include <QVBoxLayout>
#include <QInputDialog>

ListWidget::ListWidget(QWidget *parent)
: QWidget(parent) {

QVBoxLayout *vbox = new QVBoxLayout();


vbox->setSpacing(10);

QHBoxLayout *hbox = new QHBoxLayout(this);

lw = new QListWidget(this);
lw->addItem("The Omen");
lw->addItem("The Exorcist");
lw->addItem("Notes on a scandal");
lw->addItem("Fargo");
lw->addItem("Capote");

add = new QPushButton("Add", this);


rename = new QPushButton("Rename", this);
remove = new QPushButton("Remove", this);
removeAll = new QPushButton("Remove All", this);

vbox->setSpacing(3);
vbox->addStretch(1);
vbox->addWidget(add);
vbox->addWidget(rename);
vbox->addWidget(remove);
vbox->addWidget(removeAll);
vbox->addStretch(1);

hbox->addWidget(lw);
hbox->addSpacing(15);
hbox->addLayout(vbox);

connect(add, &QPushButton::clicked, this, &ListWidget::addItem);


connect(rename, &QPushButton::clicked, this, &ListWidget::renameItem);
connect(remove, &QPushButton::clicked, this, &ListWidget::removeItem);
connect(removeAll, &QPushButton::clicked, this, &ListWidget::clearItems);

setLayout(hbox);
}

void ListWidget::addItem() {

QString c_text = QInputDialog::getText(this, "Item", "Enter new item");


QString s_text = c_text.simplified();

if (!s_text.isEmpty()) {

lw->addItem(s_text);
int r = lw->count() - 1;
lw->setCurrentRow(r);
}
}

void ListWidget::renameItem() {

QListWidgetItem *curitem = lw->currentItem();

int r = lw->row(curitem);
QString c_text = curitem->text();
QString r_text = QInputDialog::getText(this, "Item",
"Enter new item", QLineEdit::Normal, c_text);

QString s_text = r_text.simplified();

if (!s_text.isEmpty()) {

QListWidgetItem *item = lw->takeItem(r);


delete item;
lw->insertItem(r, s_text);
lw->setCurrentRow(r);
}
}

void ListWidget::removeItem() {

int r = lw->currentRow();

if (r != -1) {

QListWidgetItem *item = lw->takeItem(r);


delete item;
}
}

void ListWidget::clearItems(){

if (lw->count() != 0) {
lw->clear();
}
}

We display a list widget and four buttons. We will use these buttons to add, rename, and remove
items from the list widget.

lw = new QListWidget(this);
lw->addItem("The Omen");
lw->addItem("The Exorcist");
lw->addItem("Notes on a scandal");
lw->addItem("Fargo");
lw->addItem("Capote);

The QListWidget is created and filled with five items.

void ListWidget::addItem() {

QString c_text = QInputDialog::getText(this, "Item", "Enter new item");


QString s_text = c_text.simplified();

if (!s_text.isEmpty()) {

lw->addItem(s_text);
int r = lw->count() - 1;
lw->setCurrentRow(r);
}
}

The addItem() method adds a new item to the list widget. The method pops up an input dialog. The
dialog returns a string value. We remove possible white spaces from the string using the
simplified() method. If the returned string is not empty, we add it to the list widget, at the end of

the list. Finally, we highlight the currently inserted item with the setCurrentRow() method.

void ListWidget::renameItem() {

QListWidgetItem *curitem = lw->currentItem();

int r = lw->row(curitem);
QString c_text = curitem->text();
QString r_text = QInputDialog::getText(this, "Item",
"Enter new item", QLineEdit::Normal, c_text);

QString s_text = r_text.simplified();

if (!s_text.isEmpty()) {

QListWidgetItem *item = lw->takeItem(r);


delete item;
lw->insertItem(r, s_text);
lw->setCurrentRow(r);
}
}

Renaming an item consists of several steps. First, we get the current item using the currentItem()
method. We get the text of the item and the row where the item is located. The text of the item is
displayed in the QInputDialog dialog. The string that is returned from the dialog is processed by the
simplified() method to remove potential white spaces. Then we remove the old item with the

takeItem() method and replace it with the insertItem() method. We delete the item removed by

the takeItem() method, since removed items are no longer managed by Qt. Finally, the
setCurrentRow() selects the new item.

void ListWidget::removeItem() {

int r = lw->currentRow();

if (r != -1) {

QListWidgetItem *item = lw->takeItem(r);


delete item;
}
}

The removeItem() removes a specific item from the list. First, we get the currently selected row
with the currentRow() method. (It returns -1 if there are no more rows left.) The currently selected
item is removed using the takeItem() method.
void ListWidget::clearItems(){

if (lw->count() != 0) {
lw->clear();
}
}

The clear() method removes all items from the list widget.

main.cpp
#include <QApplication>
#include "listwidget.h"

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

QApplication app(argc, argv);

ListWidget window;

window.setWindowTitle("QListWidget");
window.show();

return app.exec();
}

This is the main file.

Figure: QListWidget

QProgressBar
QProgressBar is used to give the user an indication of the progress of an operation.

progressbar.h
#pragma once

#include <QWidget>
#include <QProgressBar>
#include <QPushButton>
class ProgressBarEx : public QWidget {

Q_OBJECT

public:
ProgressBarEx(QWidget *parent = 0);

private:
int progress;
QTimer *timer;
QProgressBar *pbar;
QPushButton *startBtn;
QPushButton *stopBtn;
static const int DELAY = 200;
static const int MAX_VALUE = 100;

void updateBar();
void startMyTimer();
void stopMyTimer();
};

The header file for the example.

progressbar.cpp
#include <QProgressBar>
#include <QTimer>
#include <QGridLayout>
#include "progressbar.h"

ProgressBarEx::ProgressBarEx(QWidget *parent)
: QWidget(parent) {

progress = 0;
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);

QGridLayout *grid = new QGridLayout(this);


grid->setColumnStretch(2, 1);

pbar = new QProgressBar();


grid->addWidget(pbar, 0, 0, 1, 3);

startBtn = new QPushButton("Start", this);


connect(startBtn, &QPushButton::clicked, this, &ProgressBarEx::startMyTimer);
grid->addWidget(startBtn, 1, 0, 1, 1);

stopBtn = new QPushButton("Stop", this);


connect(stopBtn, &QPushButton::clicked, this, &ProgressBarEx::stopMyTimer);
grid->addWidget(stopBtn, 1, 1);
}

void ProgressBarEx::startMyTimer() {

if (progress >= MAX_VALUE) {


progress = 0;
pbar->setValue(0);
}

if (!timer->isActive()) {

startBtn->setEnabled(false);
stopBtn->setEnabled(true);
timer->start(DELAY);
}
}

void ProgressBarEx::stopMyTimer() {

if (timer->isActive()) {

startBtn->setEnabled(true);
stopBtn->setEnabled(false);
timer->stop();
}
}

void ProgressBarEx::updateBar() {

progress++;

if (progress <= MAX_VALUE) {

pbar->setValue(progress);
} else {

timer->stop();
startBtn->setEnabled(true);
stopBtn->setEnabled(false);
}
}

In the example, we have a QProgressBar and two push buttons. One button starts the timer, which
in turn updates the progress bar. The other button stops the timer.

timer = new QTimer(this);


connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar);

A QTimer is used to control the QProgressBar widget.

pbar = new QProgressBar();

An instance of a QProgressBar is created. The default minimum and maximum values are 0 and
100.

if (!timer->isActive()) {

startBtn->setEnabled(false);
stopBtn->setEnabled(true);
timer->start(DELAY);
}

Depending on the state of the progress bar, the buttons are enabled or disabled. This is
accomplished with the setEnabled() method.

void ProgressBarEx::updateBar() {

progress++;

if (progress <= MAX_VALUE) {

pbar->setValue(progress);
} else {

timer->stop();
startBtn->setEnabled(true);
stopBtn->setEnabled(false);
}
}

The progress is stored in the progress variable. The setValue() updates the current value of the
progress bar.

main.cpp
#include <QApplication>
#include "progressbar.h"

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

QApplication app(argc, argv);

ProgressBarEx window;

window.resize(250, 150);
window.setWindowTitle("QProgressBar");
window.show();

return app.exec();
}

This is the main file.


Figure: QProgressBar

QPixmap
QPixmap is one of the widgets used to work with images. It is optimized for showing images on

screen. In our code example, we will use QPixmap to display an image on the window.

pixmap.h
#pragma once

#include <QWidget>

class Pixmap : public QWidget {

public:
Pixmap(QWidget *parent = 0);
};

The header file for the example.

pixmap.cpp
#include <QPixmap>
#include <QLabel>
#include <QHBoxLayout>
#include "pixmap.h"

Pixmap::Pixmap(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);

QPixmap pixmap("bojnice.jpg");

QLabel *label = new QLabel(this);


label->setPixmap(pixmap);

hbox->addWidget(label, 0, Qt::AlignTop);
}

We show an image of a famous castle located in middle Slovakia.

QPixmap pixmap("bojnice.jpg");
QLabel *label = new QLabel(this);
label->setPixmap(pixmap);

We create a pixmap and put it inside a label widget.

main.cpp
#include <QApplication>
#include "pixmap.h"

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

QApplication app(argc, argv);

Pixmap window;

window.setWindowTitle("QPixmap");
window.show();

return app.exec();
}

This is the main file.

QSplitter

QSplitter lets the user control the size of child widgets by dragging the boundary between the

children. In our example, we show three QFrame widgets organized with two splitters.

splitter.h
#pragma once

#include <QWidget>

class Splitter : public QWidget {

public:
Splitter(QWidget *parent = 0);
};

The header file for the example.

splitter.cpp
#include <QFrame>
#include <QSplitter>
#include <QHBoxLayout>
#include "splitter.h"

Splitter::Splitter(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);


QFrame *topleft = new QFrame(this);
topleft->setFrameShape(QFrame::StyledPanel);

QFrame *topright = new QFrame(this);


topright->setFrameShape(QFrame::StyledPanel);

QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);


splitter1->addWidget(topleft);
splitter1->addWidget(topright);

QFrame *bottom = new QFrame(this);


bottom->setFrameShape(QFrame::StyledPanel);

QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);


splitter2->addWidget(splitter1);
splitter2->addWidget(bottom);

QList<int> sizes({50, 100});


splitter2->setSizes(sizes);

hbox->addWidget(splitter2);
}

In the example, we have three frame widgets and two splitter widgets.

QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);


splitter1->addWidget(topleft);
splitter1->addWidget(topright);

We create a splitter widget and add two frame widgets into the splitter.

QSplitter *splitter2 = new QSplitter(Qt::Vertical, this);


splitter2->addWidget(splitter1);

We can also add a splitter to another splitter widget.

QList<int> sizes({50, 100});


splitter2->setSizes(sizes);

With the setSizes() method, we set the size for the splitter's child widgets.

main.cpp
#include <QDesktopWidget>
#include <QApplication>
#include "splitter.h"

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

QApplication app(argc, argv);

Splitter window;

window.resize(350, 300);
window.setWindowTitle("QSplitter");
window.show();

return app.exec();
}

This is the main file.

Figure: QSplitter

In some desktop themes, the splitter might not be visible very well.

QTableWidget
QTableWidget is a unique widget used in spreadsheet applications. (It is also called a grid widget). It

is one of the more complicated widgets. Here we only display the widget on the window.

table.h
#pragma once

#include <QWidget>

class Table : public QWidget {

public:
Table(QWidget *parent = 0);
};

The header file for the example.

table.cpp
#include <QHBoxLayout>
#include <QTableWidget>
#include "table.h"
Table::Table(QWidget *parent)
: QWidget(parent) {

QHBoxLayout *hbox = new QHBoxLayout(this);

QTableWidget *table = new QTableWidget(25, 25, this);

hbox->addWidget(table);
}

The example shows a QTableWidget on the window.

QTableWidget *table = new QTableWidget(25, 25, this);

Here we create the table widget with 25 rows and 25 columns.

main.cpp
#include <QApplication>
#include "table.h"

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

QApplication app(argc, argv);

Table window;

window.resize(400, 250);
window.setWindowTitle("QTableWidget");
window.show();

return app.exec();
}

This is the main file.

Figure: QTableWidget

In this chapter, we have described several other Qt5 widgets.


Painting in Qt5
In this part of the Qt5 C++ programming tutorial we will do some painting.

The QPainter class is instrumental when we do some painting in Qt5. The painting is done with the
QPainter class in a reaction to the paintEvent() method.

Lines
In the first example we will paint some lines on the client area of the window.

lines.h
#pragma once

#include <QWidget>

class Lines : public QWidget {

public:
Lines(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);
void drawLines(QPainter *qp);
};

This is the header file.

lines.cpp
#include <QPainter>
#include "lines.h"

Lines::Lines(QWidget *parent)
: QWidget(parent)
{ }

void Lines::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

QPainter qp(this);
drawLines(&qp);
}

void Lines::drawLines(QPainter *qp) {

QPen pen(Qt::black, 2, Qt::SolidLine);


qp->setPen(pen);
qp->drawLine(20, 40, 250, 40);

pen.setStyle(Qt::DashLine);
qp->setPen(pen);
qp->drawLine(20, 80, 250, 80);

pen.setStyle(Qt::DashDotLine);
qp->setPen(pen);
qp->drawLine(20, 120, 250, 120);

pen.setStyle(Qt::DotLine);
qp->setPen(pen);
qp->drawLine(20, 160, 250, 160);

pen.setStyle(Qt::DashDotDotLine);
qp->setPen(pen);
qp->drawLine(20, 200, 250, 200);

QVector<qreal> dashes;
qreal space = 4;

dashes << 1 << space << 5 << space;

pen.setStyle(Qt::CustomDashLine);
pen.setDashPattern(dashes);

qp->setPen(pen);
qp->drawLine(20, 240, 250, 240);
}

We paint six lines on the window; each of the lines has a different pen style.

void Lines::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

QPainter qp(this);
drawLines(&qp);
}

The paintEvent() is called when a widget is updated. It is where we create the QPainter object and
do the drawing. Since we do not utilise the QPaintEvent object, we suppress the compiler warning
with the Q_UNUSED macro. The real drawing is delegated to the drawLines() method.

QPen pen(Qt::black, 2, Qt::SolidLine);


qp->setPen(pen);

We create a QPen object. The pen is solid, 2 px thick, and of black colour. The pen is used to draw
lines and outlines of shapes. The pen is set to the painter object with the setPen() method.

qp->drawLine(20, 40, 250, 40);

The drawLine() method draws a line. The four parameters are the coordinates of two points on the
window.

pen.setStyle(Qt::DashLine);

The setStyle() method of the QPen line sets a pen style—a Qt::DashLine.

main.cpp
#include <QApplication>
#include "lines.h"

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

QApplication app(argc, argv);

Lines window;

window.resize(280, 270);
window.setWindowTitle("Lines");
window.show();

return app.exec();
}

This is the main file.

Figure: Lines

Colours
A colour is an object representing a combination of Red, Green, and Blue (RGB) intensity values.
Valid RGB values are in the range 0 to 255. In the following example, we draw nine rectangles filled
with nine different colours.

colours.h
#pragma once

#include <QWidget>

class Colours : public QWidget {

public:
Colours(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

colours.cpp
#include <QPainter>
#include "colours.h"

Colours::Colours(QWidget *parent)
: QWidget(parent)
{ }

void Colours::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void Colours::doPainting() {

QPainter painter(this);
painter.setPen(QColor("#d4d4d4"));

painter.setBrush(QBrush("#c56c00"));
painter.drawRect(10, 15, 90, 60);

painter.setBrush(QBrush("#1ac500"));
painter.drawRect(130, 15, 90, 60);

painter.setBrush(QBrush("#539e47"));
painter.drawRect(250, 15, 90, 60);

painter.setBrush(QBrush("#004fc5"));
painter.drawRect(10, 105, 90, 60);

painter.setBrush(QBrush("#c50024"));
painter.drawRect(130, 105, 90, 60);
painter.setBrush(QBrush("#9e4757"));
painter.drawRect(250, 105, 90, 60);

painter.setBrush(QBrush("#5f3b00"));
painter.drawRect(10, 195, 90, 60);

painter.setBrush(QBrush("#4c4c4c"));
painter.drawRect(130, 195, 90, 60);

painter.setBrush(QBrush("#785f36"));
painter.drawRect(250, 195, 90, 60);
}

We draw nine rectangles with different colour fills. The outline of the rectangles is gray.

painter.setBrush(QBrush("#c56c00"));
painter.drawRect(10, 15, 90, 60);

The QBrush class defines the fill pattern of shapes drawn by QPainter. The drawRect() method
draws a rectangle. It draws a rectangle with upper left corner at x, y point and with the given width
and height. We used a hexadecimal notation to specify a colour value.

main.cpp
#include <QApplication>
#include "colours.h"

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

QApplication app(argc, argv);

Colours window;

window.resize(360, 280);
window.setWindowTitle("Colours");
window.show();

return app.exec();
}

This is the main file.


Figure: Colours

Patterns
The following programming code example is similar to the previous one. This time we fill the
rectangles with various predefined patterns.

patterns.h
#pragma once

#include <QWidget>

class Patterns : public QWidget {

public:
Patterns(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

patterns.cpp
#include <QApplication>
#include <QPainter>
#include "patterns.h"

Patterns::Patterns(QWidget *parent)
: QWidget(parent)
{ }

void Patterns::paintEvent(QPaintEvent *e) {


Q_UNUSED(e);

doPainting();
}

void Patterns::doPainting() {

QPainter painter(this);
painter.setPen(Qt::NoPen);

painter.setBrush(Qt::HorPattern);
painter.drawRect(10, 15, 90, 60);

painter.setBrush(Qt::VerPattern);
painter.drawRect(130, 15, 90, 60);

painter.setBrush(Qt::CrossPattern);
painter.drawRect(250, 15, 90, 60);

painter.setBrush(Qt::Dense7Pattern);
painter.drawRect(10, 105, 90, 60);

painter.setBrush(Qt::Dense6Pattern);
painter.drawRect(130, 105, 90, 60);

painter.setBrush(Qt::Dense5Pattern);
painter.drawRect(250, 105, 90, 60);

painter.setBrush(Qt::BDiagPattern);
painter.drawRect(10, 195, 90, 60);

painter.setBrush(Qt::FDiagPattern);
painter.drawRect(130, 195, 90, 60);

painter.setBrush(Qt::DiagCrossPattern);
painter.drawRect(250, 195, 90, 60);
}

We draw nine rectangles with various brush patterns.

painter.setBrush(Qt::HorPattern);
painter.drawRect(10, 15, 90, 60);

We draw a rectangle with a specific pattern. The Qt::HorPattern is a constant used to create a
pattern of horizontal lines.

main.cpp
#include <QDesktopWidget>
#include <QApplication>
#include "patterns.h"

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

QApplication app(argc, argv);


Patterns window;

window.resize(350, 280);
window.setWindowTitle("Patterns");
window.show();

return app.exec();
}

This is the main file.

Figure: Patterns

Transparent rectangles
Transparency is the quality of being able to see through a material. The easiest way to understand
transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the
glass and this way we can see objects behind the glass.

In computer graphics, we can achieve transparency effects using alpha compositing. Alpha
compositing is the process of combining an image with a background to create the appearance of
partial transparency. The composition process uses an alpha channel.

transparent_rectangles.h
#pragma once

#include <QWidget>

class TransparentRectangles : public QWidget {

public:
TransparentRectangles(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);
void doPainting();
};

This is the header file.

transparent_rectangles.cpp
#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include "transparent_rectangles.h"

TransparentRectangles::TransparentRectangles(QWidget *parent)
: QWidget(parent)
{ }

void TransparentRectangles::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void TransparentRectangles::doPainting() {

QPainter painter(this);

for (int i=1; i<=11; i++) {


painter.setOpacity(i*0.1);
painter.fillRect(50*i, 20, 40, 40, Qt::darkGray);
}
}

The example draws ten rectangles with different levels of transparency.

painter.setOpacity(i*0.1);

The setOpacity() method sets the opacity of the painter. The value should be in the range 0.0 to
1.0, where 0.0 is fully transparent and 1.0 is fully opaque.

main.cpp
#include <QDesktopWidget>
#include <QApplication>
#include "transparent_rectangles.h"

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

QApplication app(argc, argv);

TransparentRectangles window;

window.resize(630, 90);
window.setWindowTitle("Transparent rectangles");
window.show();

return app.exec();
}

This is the main file.

Figure: Transparent rectangles

Donut
In the following example, we will create a donut shape.

donut.h
#pragma once

#include <QWidget>

class Donut : public QWidget {

public:
Donut(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

donut.cpp
#include <QApplication>
#include <QPainter>
#include "donut.h"

Donut::Donut(QWidget *parent)
: QWidget(parent)
{ }

void Donut::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void Donut::doPainting() {
QPainter painter(this);

painter.setPen(QPen(QBrush("#535353"), 0.5));
painter.setRenderHint(QPainter::Antialiasing);

int h = height();
int w = width();

painter.translate(QPoint(w/2, h/2));

for (qreal rot=0; rot < 360.0; rot+=5.0 ) {


painter.drawEllipse(-125, -40, 250, 80);
painter.rotate(5.0);
}
}

The "Donut" is an advanced geometrical shape resembling this kind of food. We create it by
drawing 72 rotated ellipses.

painter.setRenderHint(QPainter::Antialiasing);

We will paint in antialiased mode. The rendering will be of higher quality.

int h = height();
int w = width();

painter.translate(QPoint(w/2, h/2));

These lines move the beginning of the coordinate system into the middle of the window. By default,
it is positioned at 0, 0 point. In another words, at the upper left corner of the window. By moving
the coordinate system, the drawing will be much easier.

for (qreal rot=0; rot < 360.0; rot+=5.0 ) {


painter.drawEllipse(-125, -40, 250, 80);
painter.rotate(5.0);
}

In this for cycle, we draw 72 rotated ellipses.

main.cpp
#include <QDesktopWidget>
#include <QApplication>
#include "donut.h"

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

QApplication app(argc, argv);

Donut window;

window.resize(350, 280);
window.setWindowTitle("Donut");
window.show();

return app.exec();
}

This is the main file.

Shapes
The Qt5 painting API can draw various shapes. The following programming code example shows
some of them.

shapes.h
#pragma once

#include <QWidget>

class Shapes : public QWidget {

public:
Shapes(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

shapes.cpp
#include <QApplication>
#include <QPainter>
#include <QPainterPath>
#include "shapes.h"

Shapes::Shapes(QWidget *parent)
: QWidget(parent)
{ }

void Shapes::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void Shapes::doPainting() {

QPainter painter(this);

painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(QBrush("#888"), 1));
painter.setBrush(QBrush(QColor("#888")));

QPainterPath path1;

path1.moveTo(5, 5);
path1.cubicTo(40, 5, 50, 50, 99, 99);
path1.cubicTo(5, 99, 50, 50, 5, 5);
painter.drawPath(path1);

painter.drawPie(130, 20, 90, 60, 30*16, 120*16);


painter.drawChord(240, 30, 90, 60, 0, 16*180);
painter.drawRoundRect(20, 120, 80, 50);

QPolygon polygon({QPoint(130, 140), QPoint(180, 170), QPoint(180, 140),


QPoint(220, 110), QPoint(140, 100)});

painter.drawPolygon(polygon);

painter.drawRect(250, 110, 60, 60);

QPointF baseline(20, 250);


QFont font("Georgia", 55);
QPainterPath path2;
path2.addText(baseline, font, "Q");
painter.drawPath(path2);

painter.drawEllipse(140, 200, 60, 60);


painter.drawEllipse(240, 200, 90, 60);
}

We draw nine different shapes.

QPainterPath path1;

path1.moveTo(5, 5);
path1.cubicTo(40, 5, 50, 50, 99, 99);
path1.cubicTo(5, 99, 50, 50, 5, 5);
painter.drawPath(path1);

The QPainterPath is an object used to create complex shapes. We use it to draw bezier curves.

painter.drawPie(130, 20, 90, 60, 30*16, 120*16);


painter.drawChord(240, 30, 90, 60, 0, 16*180);
painter.drawRoundRect(20, 120, 80, 50);

These code lines draw a pie, a chord, and a rounded rectangle.

QPolygon polygon({QPoint(130, 140), QPoint(180, 170), QPoint(180, 140),


QPoint(220, 110), QPoint(140, 100)});

painter.drawPolygon(polygon);

Here we draw a polygon using the drawPolygon() method. The polygon consists of five points.
QPointF baseline(20, 250);
QFont font("Georgia", 55);
QPainterPath path2;
path2.addText(baseline, font, "Q");
painter.drawPath(path2);

Qt5 allows to create a path based on a font character.

painter.drawEllipse(140, 200, 60, 60);


painter.drawEllipse(240, 200, 90, 60);

The drawEllipse() draws an ellipse and a circle as well. The circle is a special case of an ellipse.
The parameters are the x and y coordinates of the rectangle beginning and the width and height of
the bounding rectangle of the ellipse.

main.cpp
#include <QDesktopWidget>
#include <QApplication>
#include "shapes.h"

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

QApplication app(argc, argv);

Shapes window;

window.resize(350, 280);
window.setWindowTitle("Shapes");
window.show();

return app.exec();
}

This is the example's main file.

Figure: Shapes
Gradients
In computer graphics, gradient is a smooth blending of shades from light to dark or from one
colour to another. In 2D drawing programs and paint programs, gradients are used to create
colourful backgrounds and special effects as well as to simulate lights and shadows.

The following code example shows how to create linear gradients.

linear_gradients.h
#pragma once

#include <QWidget>

class LinearGradients : public QWidget {

public:
LinearGradients(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

linear_gradients.cpp
#include <QApplication>
#include <QPainter>
#include "linear_gradients.h"

LinearGradients::LinearGradients(QWidget *parent)
: QWidget(parent)
{ }

void LinearGradients::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void LinearGradients::doPainting() {

QPainter painter(this);

QLinearGradient grad1(0, 20, 0, 110);

grad1.setColorAt(0.1, Qt::black);
grad1.setColorAt(0.5, Qt::yellow);
grad1.setColorAt(0.9, Qt::black);
painter.fillRect(20, 20, 300, 90, grad1);

QLinearGradient grad2(0, 55, 250, 0);

grad2.setColorAt(0.2, Qt::black);
grad2.setColorAt(0.5, Qt::red);
grad2.setColorAt(0.8, Qt::black);

painter.fillRect(20, 140, 300, 100, grad2);


}

In the code example, we draw two rectagles and fill them with linear gradients.

QLinearGradient grad1(0, 20, 0, 110);

The QLinearGradient constructs a linear gradient with interpolation area between two points
provided as parameters.

grad1.setColorAt(0.1, Qt::black);
grad1.setColorAt(0.5, Qt::yellow);
grad1.setColorAt(0.9, Qt::black);

The colours in a gradient are defined using stop points. The setColorAt() creates a stop point at
the given position with the given colour.

painter.fillRect(20, 20, 300, 90, grad1);

We fill the rectangle with the gradient.

main.cpp
#include <QApplication>
#include "linear_gradients.h"

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

QApplication app(argc, argv);

LinearGradients window;

window.resize(350, 260);
window.setWindowTitle("Linear gradients");
window.show();

return app.exec();
}

This is the main file.


Figure: Linear gradients

Radial gradient
Radial gradients are blendings of colours or shades of colours between two circles.

radial_gradient.h
#pragma once

#include <QWidget>

class RadialGradient : public QWidget {

public:
RadialGradient(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);

private:
void doPainting();
};

This is the header file.

radial_gradient.cpp
#include <QApplication>
#include <QPainter>
#include "radial_gradient.h"

RadialGradient::RadialGradient(QWidget *parent)
: QWidget(parent)
{ }

void RadialGradient::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);
doPainting();
}

void RadialGradient::doPainting() {

QPainter painter(this);

int h = height();
int w = width();

QRadialGradient grad1(w/2, h/2, 80);

grad1.setColorAt(0, QColor("#032E91"));
grad1.setColorAt(0.3, Qt::white);
grad1.setColorAt(1, QColor("#032E91"));

painter.fillRect(0, 0, w, h, grad1);
}

The example creates a radial gradient; the gradient spreads from the center of the window.

QRadialGradient grad1(w/2, h/2, 80);

QRadialGradient creates a radial gradient; it interpolates colours between a focal point and end

points on a circle surrounding it. The parameters are coordinates of the circle's center point and its
radius. The focal point lies at the center of the circle.

grad1.setColorAt(0, QColor("#032E91"));
grad1.setColorAt(0.3, Qt::white);
grad1.setColorAt(1, QColor("#032E91"));

The setColorAt() method defines coloured stops.

painter.fillRect(0, 0, w, h, grad1);

The whole area of the window is filled with the radial gradient.

main.cpp
#include <QApplication>
#include "radial_gradient.h"

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

QApplication app(argc, argv);

RadialGradient window;

window.resize(300, 250);
window.setWindowTitle("Radial gradient");
window.show();

return app.exec();
}
This is the main file.

Figure: Radial gradient

Puff
In the last example of this C++ Qt5 tutorial chapter, we create a puff effect. The example displays a
growing centered text that gradully fades out from some point. This is a very common effect, which
you can often see in flash animations on the web.

puff.h
#pragma once

#include <QWidget>

class Puff : public QWidget {

public:
Puff(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *event);
void timerEvent(QTimerEvent *event);

private:
int x;
qreal opacity;
int timerId;

void doPainting();
};

In the header file, we have two event handlers defined: paint event handler and timer handler.

puff.cpp
#include <QPainter>
#include <QTimer>
#include <QTextStream>
#include "puff.h"

Puff::Puff(QWidget *parent)
: QWidget(parent) {

x = 1;
opacity = 1.0;
timerId = startTimer(15);
}

void Puff::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doPainting();
}

void Puff::doPainting() {

QPainter painter(this);
QTextStream out(stdout);

QString text = "ZetCode";

painter.setPen(QPen(QBrush("#575555"), 1));

QFont font("Courier", x, QFont::DemiBold);


QFontMetrics fm(font);
int textWidth = fm.width(text);

painter.setFont(font);

if (x > 10) {
opacity -= 0.01;
painter.setOpacity(opacity);
}

if (opacity <= 0) {
killTimer(timerId);
out << "timer stopped" << endl;
}

int h = height();
int w = width();

painter.translate(QPoint(w/2, h/2));
painter.drawText(-textWidth/2, 0, text);
}

void Puff::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

x += 1;
repaint();
}
This is the puff.cpp file.

Puff::Puff(QWidget *parent)
: QWidget(parent) {

x = 1;
opacity = 1.0;
timerId = startTimer(15);
}

At the constructor, we start the timer. Each 15 ms a timer event is generated.

void Puff::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

x += 1;
repaint();
}

Inside the timerEvent() we increase the font size and repaint the widget.

if (x > 10) {
opacity -= 0.01;
painter.setOpacity(opacity);
}

If the font size is greater than 10 points, we gradually decrease the opacity; the text starts to fade
away.

if (opacity <= 0) {
killTimer(timerId);
out << "timer stopped" << endl;
}

If the text completely fades away, we kill the timer.

main.cpp
#include <QApplication>
#include "puff.h"

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

QApplication app(argc, argv);

Puff window;

window.resize(350, 280);
window.setWindowTitle("Puff");
window.show();
return app.exec();
}

This is the main file.

This chapter was about painting in Qt5.


Custom widget in Qt5
In this part of the Qt5 C++ programming tutorial, we will create a custom widget.

Most toolkits usually provide only the most common widgets like buttons, text widgets, or sliders.
No toolkit can provide all possible widgets. Programmers must create such widgets by themselves.
They do it by using the drawing tools provided by the toolkit. There are two possibilities: a
programmer can modify or enhance an existing widget or he can create a custom widget from
scratch.

The Burning widget


In the next example we create a custom Burning widget. This widget can be seen in applications
like Nero or K3B. The widget will be created from scratch.

burning.h
#pragma once

#include <QWidget>
#include <QSlider>
#include <QFrame>
#include "widget.h"

class Burning : public QFrame {

Q_OBJECT

public:
Burning(QWidget *parent = 0);
int getCurrentWidth();

public slots:
void valueChanged(int);

private:
QSlider *slider;
Widget *widget;
int cur_width;

void initUI();
};
This is the header file of the main window of the example.

public:
Burning(QWidget *parent = 0);
int getCurrentWidth();

The getCurrentWidth() method is going to be used to determine the slider value.

private:
QSlider *slider;
Widget *widget;
int cur_width;

void initUI();

We will have two widgets on the client area of the window: A built-in slider widget and a custom
widget. The cur_width variable will hold the current value from the slider. This value is used when
painting the custom widget.

burning.cpp
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "burning.h"

Burning::Burning(QWidget *parent)
: QFrame(parent) {

initUI();
}

void Burning::initUI() {

const int MAX_VALUE = 750;


cur_width = 0;

slider = new QSlider(Qt::Horizontal , this);


slider->setMaximum(MAX_VALUE);
slider->setGeometry(50, 50, 130, 30);

connect(slider, &QSlider::valueChanged, this, &Burning::valueChanged);

QVBoxLayout *vbox = new QVBoxLayout(this);


QHBoxLayout *hbox = new QHBoxLayout();

vbox->addStretch(1);

widget = new Widget(this);


hbox->addWidget(widget, 0);

vbox->addLayout(hbox);

setLayout(vbox);
}
void Burning::valueChanged(int val) {

cur_width = val;
widget->repaint();
}

int Burning::getCurrentWidth() {

return cur_width;
}

Here we build the main window of the example.

connect(slider, &QSlider::valueChanged, this, &Burning::valueChanged);

When we move the slider, the valueChanged() slot is executed.

void Burning::valueChanged(int val) {

cur_width = val;
widget->repaint();
}

When we change the value of the slider, we store the new value and repaint the custom widget.

widget.h
#pragma once

#include <QFrame>

class Burning;

class Widget : public QFrame {

public:
Widget(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *e);
void drawWidget(QPainter &qp);

private:
QWidget *m_parent;
Burning *burn;

static const int DISTANCE = 19;


static const int LINE_WIDTH = 5;
static const int DIVISIONS = 10;
static const float FULL_CAPACITY = 700;
static const float MAX_CAPACITY = 750;
};

This is the header file of the custom burning widget.


private:
QWidget *m_parent;
Burning *burn;

We store a pointer to the parent widget. We get the cur_width through this pointer.

const int DISTANCE = 19;


const int LINE_WIDTH = 5;
const int DIVISIONS = 10;
const float FULL_CAPACITY = 700;
const float MAX_CAPACITY = 750;

These are the important constants. The DISTANCE is the distance of the numbers on the scale from
the top of their parent border. The LINE_WIDTH is the vertical line width. The DIVISIONS is the
number of parts of the scale. The FULL_CAPACITY is the capacity of the media. After it is reached,
overburning happens. This is visualized by a red colour. The MAX_CAPACITY is the maximum
capacity of a medium.

widget.cpp
#include <QtGui>
#include "widget.h"
#include "burning.h"

const int PANEL_HEIGHT = 30;

Widget::Widget(QWidget *parent)
: QFrame(parent) {

m_parent = parent;
setMinimumHeight(PANEL_HEIGHT);
}

void Widget::paintEvent(QPaintEvent *e) {

QPainter qp(this);
drawWidget(qp);

QFrame::paintEvent(e);
}

void Widget::drawWidget(QPainter &qp) {

QString num[] = { "75", "150", "225", "300", "375", "450",


"525", "600", "675" };

int asize = sizeof(num)/sizeof(num[1]);

QColor redColor(255, 175, 175);


QColor yellowColor(255, 255, 184);

int width = size().width();

Burning *burn = (Burning *) m_parent;


int cur_width = burn->getCurrentWidth();

int step = (int) qRound((double)width / DIVISIONS);


int till = (int) ((width / MAX_CAPACITY) * cur_width);
int full = (int) ((width / MAX_CAPACITY) * FULL_CAPACITY);

if (cur_width >= FULL_CAPACITY) {

qp.setPen(yellowColor);
qp.setBrush(yellowColor);
qp.drawRect(0, 0, full, 30);
qp.setPen(redColor);
qp.setBrush(redColor);
qp.drawRect(full, 0, till-full, PANEL_HEIGHT);

} else if (till > 0) {

qp.setPen(yellowColor);
qp.setBrush(yellowColor);
qp.drawRect(0, 0, till, PANEL_HEIGHT);
}

QColor grayColor(90, 80, 60);


qp.setPen(grayColor);

for (int i=1; i <=asize; i++) {

qp.drawLine(i*step, 0, i*step, LINE_WIDTH);


QFont newFont = font();
newFont.setPointSize(7);
setFont(newFont);

QFontMetrics metrics(font());

int w = metrics.width(num[i-1]);
qp.drawText(i*step-w/2, DISTANCE, num[i-1]);
}
}

Here we paint the custom widget. We paint the rectangle, vertical lines, and the numbers.

void Widget::paintEvent(QPaintEvent *e) {

QPainter qp(this);
drawWidget(qp);

QFrame::paintEvent(e);
}

The drawing of the custom widget is delegated to the drawWidget() method.

QString num[] = { "75", "150", "225", "300", "375", "450",


"525", "600", "675" };

We use these numbers to build the scale of the Burning widget.


int width = size().width();

We get the width of the widget. The width of the custom widget is dynamic. It can be resized by the
user.

Burning *burn = (Burning *) m_parent;


int cur_width = burn->getCurrentWidth();

We get the cur_width value.

int till = (int) ((width / MAX_CAPACITY) * cur_width);


int full = (int) ((width / MAX_CAPACITY) * FULL_CAPACITY);

We use the width variable to do the transformations, between the values of the scale and the
custom widget's measures.

qp.setPen(redColor);
qp.setBrush(redColor);
qp.drawRect(full, 0, till-full, PANEL_HEIGHT);

These three lines draw the red rectangle, indicating the overburning.

qp.drawLine(i*step, 0, i*step, LINE_WIDTH);

Here we draw the small vertical lines.

QFontMetrics metrics(font());

int w = metrics.width(num[i-1]);
qp.drawText(i*step-w/2, DISTANCE, num[i-1]);

Here we draw the numbers of the scale. To precisely position the numbers, we must get the width
of the string.

main.cpp
#include <QApplication>
#include "burning.h"

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

QApplication app(argc, argv);


Burning window;

window.resize(370, 200);
window.setWindowTitle("The Burning widget");
window.show();

return app.exec();
}
This is the main file.

Figure: The Burning widget

In this part of the Qt5 tutorial, we have created a custom Burning widget.
Snake in Qt5
In this part of the Qt5 tutorial, we create a Snake game clone.

Snake
Snake is an older classic video game. It was first created in late 70s. Later it was brought to PCs. In
this game the player controls a snake. The objective is to eat as many apples as possible. Each time
the snake eats an apple, its body grows. The snake must avoid the walls and its own body. This
game is sometimes called Nibbles.

Development

The size of each of the joints of a snake is 10 px. The snake is controlled with the cursor keys.
Initially, the snake has three joints. If the game is finished, the "Game Over" message is displayed in
the middle of the board.

Snake.h
#pragma once

#include <QWidget>
#include <QKeyEvent>

class Snake : public QWidget {

public:
Snake(QWidget *parent = 0);

protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void keyPressEvent(QKeyEvent *);

private:
QImage dot;
QImage head;
QImage apple;

static const int B_WIDTH = 300;


static const int B_HEIGHT = 300;
static const int DOT_SIZE = 10;
static const int ALL_DOTS = 900;
static const int RAND_POS = 29;
static const int DELAY = 140;

int timerId;
int dots;
int apple_x;
int apple_y;

int x[ALL_DOTS];
int y[ALL_DOTS];

bool leftDirection;
bool rightDirection;
bool upDirection;
bool downDirection;
bool inGame;

void loadImages();
void initGame();
void locateApple();
void checkApple();
void checkCollision();
void move();
void doDrawing();
void gameOver(QPainter &);
};

This is the header file.

static const int B_WIDTH = 300;


static const int B_HEIGHT = 300;
static const int DOT_SIZE = 10;
static const int ALL_DOTS = 900;
static const int RAND_POS = 29;
static const int DELAY = 140;

The B_WIDTH and B_HEIGHT constants determine the size of the board. The DOT_SIZE is the size of the
apple and the dot of the snake. The ALL_DOTS constant defines the maximum number of possible
dots on the board (900 = (300*300)/(10*10)). The RAND_POS constant is used to calculate a random
position for an apple. The DELAY constant determines the speed of the game.

int x[ALL_DOTS];
int y[ALL_DOTS];
These two arrays hold the x and y coordinates of all joints of a snake.

snake.cpp
#include <QPainter>
#include <QTime>
#include "snake.h"

Snake::Snake(QWidget *parent) : QWidget(parent) {

setStyleSheet("background-color:black;");
leftDirection = false;
rightDirection = true;
upDirection = false;
downDirection = false;
inGame = true;

resize(B_WIDTH, B_HEIGHT);
loadImages();
initGame();
}

void Snake::loadImages() {

dot.load("dot.png");
head.load("head.png");
apple.load("apple.png");
}

void Snake::initGame() {

dots = 3;

for (int z = 0; z < dots; z++) {


x[z] = 50 - z * 10;
y[z] = 50;
}

locateApple();

timerId = startTimer(DELAY);
}

void Snake::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

doDrawing();
}

void Snake::doDrawing() {

QPainter qp(this);

if (inGame) {

qp.drawImage(apple_x, apple_y, apple);


for (int z = 0; z < dots; z++) {
if (z == 0) {
qp.drawImage(x[z], y[z], head);
} else {
qp.drawImage(x[z], y[z], dot);
}
}

} else {

gameOver(qp);
}
}

void Snake::gameOver(QPainter &qp) {

QString message = "Game over";


QFont font("Courier", 15, QFont::DemiBold);
QFontMetrics fm(font);
int textWidth = fm.width(message);

qp.setFont(font);
int h = height();
int w = width();

qp.translate(QPoint(w/2, h/2));
qp.drawText(-textWidth/2, 0, message);
}

void Snake::checkApple() {

if ((x[0] == apple_x) && (y[0] == apple_y)) {

dots++;
locateApple();
}
}

void Snake::move() {

for (int z = dots; z > 0; z--) {


x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}

if (leftDirection) {
x[0] -= DOT_SIZE;
}

if (rightDirection) {
x[0] += DOT_SIZE;
}

if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}

void Snake::checkCollision() {

for (int z = dots; z > 0; z--) {

if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {


inGame = false;
}
}

if (y[0] >= B_HEIGHT) {


inGame = false;
}

if (y[0] < 0) {
inGame = false;
}

if (x[0] >= B_WIDTH) {


inGame = false;
}

if (x[0] < 0) {
inGame = false;
}

if(!inGame) {
killTimer(timerId);
}
}

void Snake::locateApple() {

QTime time = QTime::currentTime();


qsrand((uint) time.msec());

int r = qrand() % RAND_POS;


apple_x = (r * DOT_SIZE);

r = qrand() % RAND_POS;
apple_y = (r * DOT_SIZE);
}

void Snake::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

if (inGame) {

checkApple();
checkCollision();
move();
}
repaint();
}

void Snake::keyPressEvent(QKeyEvent *e) {

int key = e->key();

if ((key == Qt::Key_Left) && (!rightDirection)) {


leftDirection = true;
upDirection = false;
downDirection = false;
}

if ((key == Qt::Key_Right) && (!leftDirection)) {


rightDirection = true;
upDirection = false;
downDirection = false;
}

if ((key == Qt::Key_Up) && (!downDirection)) {


upDirection = true;
rightDirection = false;
leftDirection = false;
}

if ((key == Qt::Key_Down) && (!upDirection)) {


downDirection = true;
rightDirection = false;
leftDirection = false;
}

QWidget::keyPressEvent(e);
}

In the snake.cpp file, we have the logic of the game.

void Snake::loadImages() {

dot.load("dot.png");
head.load("head.png");
apple.load("apple.png");
}

In the loadImages() method we get the images for the game. The ImageIcon class is used for
displaying PNG images.

void Snake::initGame() {

dots = 3;

for (int z = 0; z < dots; z++) {


x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();

timerId = startTimer(DELAY);
}

In the initGame() method we create the snake, randomly locate an apple on the board, and start
the timer.

void Snake::checkApple() {

if ((x[0] == apple_x) && (y[0] == apple_y)) {

dots++;
locateApple();
}
}

If the apple collides with the head, we increase the number of joints of the snake. We call the
locateApple() method which randomly positions a new apple object.

In the move() method we have the key algorithm of the game. To understand it, look at how the
snake is moving. We control the head of the snake. We can change its direction with the cursor
keys. The rest of the joints move one position up the chain. The second joint moves where the first
was, the third joint where the second was etc.

for (int z = dots; z > 0; z--) {


x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}

This code moves the joints up the chain.

if (leftDirection) {
x[0] -= DOT_SIZE;
}

This line moves the head to the left.

In the checkCollision() method, we determine if the snake has hit itself or one of the walls.

for (int z = dots; z > 0; z--) {

if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {


inGame = false;
}
}

If the snake hits one of its joints with its head the game is over.

if (y[0] >= B_HEIGHT) {


inGame = false;
}

The game is finished if the snake hits the bottom of the board.

void Snake::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

if (inGame) {

checkApple();
checkCollision();
move();
}

repaint();
}

The timerEvent() method forms a game cycle. Provided that the game has not finished, we
perform collision detection and do movement. The repaint() causes the window to be redrawn.

if ((key == Qt::Key_Left) && (!rightDirection)) {


leftDirection = true;
upDirection = false;
downDirection = false;
}

If we hit the left cursor key, we set the leftDirection variable to true. This variable is used in the
move() function to change the coordinates of the snake object. Notice also that when the snake is

heading to the right, we cannot turn immediately to the left.

Snake.java
#include <QApplication>
#include "snake.h"

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

QApplication app(argc, argv);

Snake window;

window.setWindowTitle("Snake");
window.show();

return app.exec();
}

This is the main class.


Figure: Snake

This was the Snake game in Qt5.


The Breakout game in Qt5
In this part of the Qt5 tutorial, we create a simple Breakout game clone.

The Breakout is an arcade game developed by Atari Inc. The game was created in 1976. In this
game, the player moves a paddle and bounces a ball. The objective is to destroy bricks in the top of
the window.

The development

In our game, we have one paddle, one ball and thirty bricks. A timer is used to create a game cycle.
We do not work with angles, we simply change directions: top, bottom, left, and right. The code was
inspired by the PyBreakout game, which was developed in PyGame library by Nathan Dawson.

The game is intentionally simple. There are no bonuses, levels, or score. It is then easier to
understand.

The Qt5 library is developed for creating computer applications. Nevertheless, it can be used to
create games as well. Developing a computer game is a great way to learn more about Qt5.

paddle.h
#pragma once

#include <QImage>
#include <QRect>

class Paddle {

public:
Paddle();
~Paddle();

public:
void resetState();
void move();
void setDx(int);
QRect getRect();
QImage & getImage();

private:
QImage image;
QRect rect;
int dx;
static const int INITIAL_X = 200;
static const int INITIAL_Y = 360;
};

This is a header file for the paddle object. The INITIAL_X and INITIAL_Y are constants which
represent the initial coordinates of the paddle object.

paddle.cpp
#include <iostream>
#include "paddle.h"

Paddle::Paddle() {

dx = 0;
image.load("paddle.png");

rect = image.rect();
resetState();
}

Paddle::~Paddle() {

std::cout << ("Paddle deleted") << std::endl;


}

void Paddle::setDx(int x) {
dx = x;
}

void Paddle::move() {

int x = rect.x() + dx;


int y = rect.top();

rect.moveTo(x, y);
}

void Paddle::resetState() {

rect.moveTo(INITIAL_X, INITIAL_Y);
}

QRect Paddle::getRect() {

return rect;
}

QImage & Paddle::getImage() {

return image;
}

The paddle can be moved to the right or to the left.


Paddle::Paddle() {

dx = 0;
image.load("paddle.png");

rect = image.rect();
resetState();
}

In the constructor, we initiate the dx variable and load the paddle image. We get the image
rectangle and move the image to its initial position.

void Paddle::move() {

int x = rect.x() + dx;


int y = rect.top();

rect.moveTo(x, y);
}

The move() method moves the paddle's rectangle. The movement direction is controlled by the dx
variable.

void Paddle::resetState() {

rect.moveTo(INITIAL_X, INITIAL_Y);
}

The resetState() moves the paddle to its initial position.

brick.h
#pragma once

#include <QImage>
#include <QRect>

class Brick {

public:
Brick(int, int);
~Brick();

public:
bool isDestroyed();
void setDestroyed(bool);
QRect getRect();
void setRect(QRect);
QImage & getImage();

private:
QImage image;
QRect rect;
bool destroyed;
};

This is the header file for the brick object. If a brick is destroyed, the destroyed variable is set to
true.

brick.cpp
#include <iostream>
#include "brick.h"

Brick::Brick(int x, int y) {

image.load("brickie.png");
destroyed = false;
rect = image.rect();
rect.translate(x, y);
}

Brick::~Brick() {

std::cout << ("Brick deleted") << std::endl;


}

QRect Brick::getRect() {

return rect;
}

void Brick::setRect(QRect rct) {

rect = rct;
}

QImage & Brick::getImage() {

return image;
}

bool Brick::isDestroyed() {

return destroyed;
}

void Brick::setDestroyed(bool destr) {

destroyed = destr;
}

The Brick class represents the brick object.

Brick::Brick(int x, int y) {

image.load("brickie.png");
destroyed = false;
rect = image.rect();
rect.translate(x, y);
}

The brick's contructor loads its image, initiates the destroyed flag, and moves the image to its initial
position.

bool Brick::isDestroyed() {

return destroyed;
}

The brick has a destroyed flag. If the destroyed flag is set, the brick is not drawn on the window.

ball.h
#pragma once

#include <QImage>
#include <QRect>

class Ball {

public:
Ball();
~Ball();

public:
void resetState();
void autoMove();
void setXDir(int);
void setYDir(int);
int getXDir();
int getYDir();
QRect getRect();
QImage & getImage();

private:
int xdir;
int ydir;
QImage image;
QRect rect;
static const int INITIAL_X = 230;
static const int INITIAL_Y = 355;
static const int RIGHT_EDGE = 300;
};

This is the header file for the ball object. The xdir and ydir variables store the direction of the ball's
movement.

ball.cpp
#include <iostream>
#include "ball.h"

Ball::Ball() {
xdir = 1;
ydir = -1;

image.load("ball.png");

rect = image.rect();
resetState();
}

Ball::~Ball() {

std::cout << ("Ball deleted") << std::endl;


}

void Ball::autoMove() {

rect.translate(xdir, ydir);

if (rect.left() == 0) {
xdir = 1;
}

if (rect.right() == RIGHT_EDGE) {
xdir = -1;
}

if (rect.top() == 0) {
ydir = 1;
}
}

void Ball::resetState() {

rect.moveTo(INITIAL_X, INITIAL_Y);
}

void Ball::setXDir(int x) {

xdir = x;
}

void Ball::setYDir(int y) {

ydir = y;
}

int Ball::getXDir() {

return xdir;
}

int Ball::getYDir() {

return ydir;
}

QRect Ball::getRect() {
return rect;
}

QImage & Ball::getImage() {

return image;
}

The Ball class represents the ball object.

xdir = 1;
ydir = -1;

At the beginning, the ball moves in north-east direction.

void Ball::autoMove() {

rect.translate(xdir, ydir);

if (rect.left() == 0) {
xdir = 1;
}

if (rect.right() == RIGHT_EDGE) {
xdir = -1;
}

if (rect.top() == 0) {
ydir = 1;
}
}

The autoMove() method is called each game cycle to move the ball on the screen. If it hists the
boundaries, the ball direction changes. If the ball passes the bottom edge, the ball does not bounce
back—the game is over.

breakout.h
#pragma once

#include <QWidget>
#include <QKeyEvent>
#include "ball.h"
#include "brick.h"
#include "paddle.h"

class Breakout : public QWidget {

public:
Breakout(QWidget *parent = 0);
~Breakout();

protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void keyPressEvent(QKeyEvent *);
void keyReleaseEvent(QKeyEvent *);
void drawObjects(QPainter *);
void finishGame(QPainter *, QString);
void moveObjects();

void startGame();
void pauseGame();
void stopGame();
void victory();
void checkCollision();

private:
int x;
int timerId;
static const int N_OF_BRICKS = 30;
static const int DELAY = 10;
static const int BOTTOM_EDGE = 400;
Ball *ball;
Paddle *paddle;
Brick *bricks[N_OF_BRICKS];
bool gameOver;
bool gameWon;
bool gameStarted;
bool paused;
};

This is the header file for the breakout object.

void keyPressEvent(QKeyEvent *);


void keyReleaseEvent(QKeyEvent *);

The paddle is controlled with the cursor keys. In the game, we listen for key press and key release
events.

int x;
int timerId;

The x variable stores the current x position of the paddle. The timerId is used for identifying of the
timer object. This is necessary when we pause the game.

static const int N_OF_BRICKS = 30;

The N_OF_BRICKS constant stores the number of bricks in the game.

static const int DELAY = 10;

The DELAY constant controls the speed of the game.

static const int BOTTOM_EDGE = 400;


When the ball passes the bottom edge, the game is over.

Ball *ball;
Paddle *paddle;
Brick *bricks[N_OF_BRICKS];

The game consists of a ball, paddle, and an array of bricks.

bool gameOver;
bool gameWon;
bool gameStarted;
bool paused;

These four variables represent various states of the game.

breakout.cpp
#include <QPainter>
#include <QApplication>
#include "breakout.h"

Breakout::Breakout(QWidget *parent)
: QWidget(parent) {

x = 0;
gameOver = false;
gameWon = false;
paused = false;
gameStarted = false;
ball = new Ball();
paddle = new Paddle();

int k = 0;

for (int i=0; i<5; i++) {


for (int j=0; j<6; j++) {
bricks[k] = new Brick(j*40+30, i*10+50);
k++;
}
}
}

Breakout::~Breakout() {

delete ball;
delete paddle;

for (int i=0; i<N_OF_BRICKS; i++) {


delete bricks[i];
}
}

void Breakout::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);
QPainter painter(this);

if (gameOver) {

finishGame(&painter, "Game lost");

} else if(gameWon) {

finishGame(&painter, "Victory");
}
else {

drawObjects(&painter);
}
}

void Breakout::finishGame(QPainter *painter, QString message) {

QFont font("Courier", 15, QFont::DemiBold);


QFontMetrics fm(font);
int textWidth = fm.width(message);

painter->setFont(font);
int h = height();
int w = width();

painter->translate(QPoint(w/2, h/2));
painter->drawText(-textWidth/2, 0, message);
}

void Breakout::drawObjects(QPainter *painter) {

painter->drawImage(ball->getRect(), ball->getImage());
painter->drawImage(paddle->getRect(), paddle->getImage());

for (int i=0; i<N_OF_BRICKS; i++) {


if (!bricks[i]->isDestroyed()) {
painter->drawImage(bricks[i]->getRect(), bricks[i]->getImage());
}
}
}

void Breakout::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

moveObjects();
checkCollision();
repaint();
}

void Breakout::moveObjects() {

ball->autoMove();
paddle->move();
}
void Breakout::keyReleaseEvent(QKeyEvent *e) {

int dx = 0;

switch (e->key()) {
case Qt::Key_Left:
dx = 0;
paddle->setDx(dx);
break;

case Qt::Key_Right:
dx = 0;
paddle->setDx(dx);
break;
}
}

void Breakout::keyPressEvent(QKeyEvent *e) {

int dx = 0;

switch (e->key()) {
case Qt::Key_Left:

dx = -1;
paddle->setDx(dx);

break;

case Qt::Key_Right:

dx = 1;
paddle->setDx(dx);
break;

case Qt::Key_P:

pauseGame();
break;

case Qt::Key_Space:

startGame();
break;

case Qt::Key_Escape:

qApp->exit();
break;

default:
QWidget::keyPressEvent(e);
}
}

void Breakout::startGame() {

if (!gameStarted) {
ball->resetState();
paddle->resetState();

for (int i=0; i<N_OF_BRICKS; i++) {


bricks[i]->setDestroyed(false);
}

gameOver = false;
gameWon = false;
gameStarted = true;
timerId = startTimer(DELAY);
}
}

void Breakout::pauseGame() {

if (paused) {

timerId = startTimer(DELAY);
paused = false;
} else {

paused = true;
killTimer(timerId);
}
}

void Breakout::stopGame() {

killTimer(timerId);
gameOver = true;
gameStarted = false;
}

void Breakout::victory() {

killTimer(timerId);
gameWon = true;
gameStarted = false;
}

void Breakout::checkCollision() {

if (ball->getRect().bottom() > BOTTOM_EDGE) {


stopGame();
}

for (int i=0, j=0; i<N_OF_BRICKS; i++) {

if (bricks[i]->isDestroyed()) {
j++;
}

if (j == N_OF_BRICKS) {
victory();
}
}
if ((ball->getRect()).intersects(paddle->getRect())) {

int paddleLPos = paddle->getRect().left();


int ballLPos = ball->getRect().left();

int first = paddleLPos + 8;


int second = paddleLPos + 16;
int third = paddleLPos + 24;
int fourth = paddleLPos + 32;

if (ballLPos < first) {


ball->setXDir(-1);
ball->setYDir(-1);
}

if (ballLPos >= first && ballLPos < second) {


ball->setXDir(-1);
ball->setYDir(-1*ball->getYDir());
}

if (ballLPos >= second && ballLPos < third) {


ball->setXDir(0);
ball->setYDir(-1);
}

if (ballLPos >= third && ballLPos < fourth) {


ball->setXDir(1);
ball->setYDir(-1*ball->getYDir());
}

if (ballLPos > fourth) {


ball->setXDir(1);
ball->setYDir(-1);
}
}

for (int i=0; i<N_OF_BRICKS; i++) {

if ((ball->getRect()).intersects(bricks[i]->getRect())) {

int ballLeft = ball->getRect().left();


int ballHeight = ball->getRect().height();
int ballWidth = ball->getRect().width();
int ballTop = ball->getRect().top();

QPoint pointRight(ballLeft + ballWidth + 1, ballTop);


QPoint pointLeft(ballLeft - 1, ballTop);
QPoint pointTop(ballLeft, ballTop -1);
QPoint pointBottom(ballLeft, ballTop + ballHeight + 1);

if (!bricks[i]->isDestroyed()) {
if(bricks[i]->getRect().contains(pointRight)) {
ball->setXDir(-1);
}

else if(bricks[i]->getRect().contains(pointLeft)) {
ball->setXDir(1);
}
if(bricks[i]->getRect().contains(pointTop)) {
ball->setYDir(1);
}

else if(bricks[i]->getRect().contains(pointBottom)) {
ball->setYDir(-1);
}

bricks[i]->setDestroyed(true);
}
}
}
}

In the breakout.cpp file, we have the game logic.

int k = 0;
for (int i=0; i<5; i++) {
for (int j=0; j<6; j++) {
bricks[k] = new Brick(j*40+30, i*10+50);
k++;
}
}

In the constructor of the Breakout object, we instantiate thirty bricks.

void Breakout::paintEvent(QPaintEvent *e) {

Q_UNUSED(e);

QPainter painter(this);

if (gameOver) {

finishGame(&painter, "Game lost");

} else if(gameWon) {

finishGame(&painter, "Victory");
}
else {

drawObjects(&painter);
}
}

Depending on the gameOver and gameWon variables, we either finish the game with a message or
paint the game objects on the window.

void Breakout::finishGame(QPainter *painter, QString message) {

QFont font("Courier", 15, QFont::DemiBold);


QFontMetrics fm(font);
int textWidth = fm.width(message);

painter->setFont(font);
int h = height();
int w = width();

painter->translate(QPoint(w/2, h/2));
painter->drawText(-textWidth/2, 0, message);
}

The finishGame() method draws a final message in the center of the window. It is either "Game
lost" or "Victory". The QFontMetrics' width() is used to compute the width of the string.

void Breakout::drawObjects(QPainter *painter) {

painter->drawImage(ball->getRect(), ball->getImage());
painter->drawImage(paddle->getRect(), paddle->getImage());

for (int i=0; i<N_OF_BRICKS; i++) {


if (!bricks[i]->isDestroyed()) {
painter->drawImage(bricks[i]->getRect(), bricks[i]->getImage());
}
}
}

The drawObjects() method draws all the objects of the game on the window: the ball, the paddle,
and the bricks. The objects are represented by images and the drawImage() method draws them on
the window.

void Breakout::timerEvent(QTimerEvent *e) {

Q_UNUSED(e);

moveObjects();
checkCollision();
repaint();
}

In the timerEvent(), we move the objects, check if the ball collided with the paddle or a brick, and
generate a paint event.

void Breakout::moveObjects() {

ball->autoMove();
paddle->move();
}

The moveObjects() method moves the ball and paddle objects. Their own move method is being
called.
void Breakout::keyReleaseEvent(QKeyEvent *e) {

int dx = 0;

switch (e->key()) {
case Qt::Key_Left:
dx = 0;
paddle->setDx(dx);
break;

case Qt::Key_Right:
dx = 0;
paddle->setDx(dx);
break;
}
}

When the player releases the Left cursor key or the Right cursor key, we set the paddle's dx
variable to zero. As a consequence, the paddle stops moving.

void Breakout::keyPressEvent(QKeyEvent *e) {

int dx = 0;

switch (e->key()) {
case Qt::Key_Left:

dx = -1;
paddle->setDx(dx);

break;

case Qt::Key_Right:

dx = 1;
paddle->setDx(dx);
break;

case Qt::Key_P:

pauseGame();
break;

case Qt::Key_Space:

startGame();
break;

case Qt::Key_Escape:

qApp->exit();
break;
default:
QWidget::keyPressEvent(e);
}
}

In the keyPressEvent() method, we listen for key press events relevant to our game. The Left and
Right cursor keys move the paddle object. They set the dx variable, which is later added to the

paddle's x coordinate. The P key pauses the game, the Space key starts the game. The Esc key exits
the application.

void Breakout::startGame() {

if (!gameStarted) {
ball->resetState();
paddle->resetState();

for (int i=0; i<N_OF_BRICKS; i++) {


bricks[i]->setDestroyed(false);
}

gameOver = false;
gameWon = false;
gameStarted = true;
timerId = startTimer(DELAY);
}
}

The startGame() method resets the ball and paddle objects; they are moved to their initial
positions. In the for loop, we reset each brick's destroyed flag to false, thus showing them all on the
window. The gameOver, gameWon, and gameStarted variables get their initial boolean values. Finally,
the timer is started with the startTimer() method.

void Breakout::pauseGame() {

if (paused) {

timerId = startTimer(DELAY);
paused = false;
} else {

paused = true;
killTimer(timerId);
}
}

The pauseGame() is used to pause and start the paused game. The state is controlled with the paused
variable. We also store the timer's Id. In order to pause the game, we kill the timer with the
killTimer() method. To restart it, we call the startTimer() method.

void Breakout::stopGame() {
killTimer(timerId);
gameOver = true;
gameStarted = false;
}

In the stopGame() method, we kill the timer and set the appropriate flags.

void Breakout::checkCollision() {

if (ball->getRect().bottom() > BOTTOM_EDGE) {


stopGame();
}
...
}

In the checkCollision() method, we do the collision detection for the game. The game is finished if
the ball hits the bottom edge.

for (int i=0, j=0; i<N_OF_BRICKS; i++) {

if (bricks[i]->isDestroyed()) {
j++;
}

if (j == N_OF_BRICKS) {
victory();
}
}

We check how many bricks are destroyed. If we destroyed all bricks, we win the game.

if (ballLPos < first) {


ball->setXDir(-1);
ball->setYDir(-1);
}

If the ball hits the first part of the paddle, we change the direction of the ball to north-west.

if(bricks[i]->getRect().contains(pointTop)) {
ball->setYDir(1);
}

If the ball hits the bottom of the brick, we change the y direction of the ball; it goes down.

main.cpp
#include <QApplication>
#include "breakout.h"

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

QApplication app(argc, argv);


Breakout window;

window.resize(300, 400);
window.setWindowTitle("Breakout");
window.show();

return app.exec();
}

This is the main file.

Figure: The Breakout game

This was the Breakout game in Qt5.

Vous aimerez peut-être aussi