ZetCode

Containers in Qt5

last modified December 4, 2020

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.

Since in this chapter we create command line programs, we do not need the Qt GUI module. We can add the QT -= gui declaration to the project file.

Qt5 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.

$ ./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

Qt5 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;
    }

    return 0;
}

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.

$ ./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;
    }

    return 0;
}

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.

$ ./mystringlist
coin
book
cup
pencil
clock
bookmark

Qt5 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.

$ ./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

Qt5 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;
    }

    return 0;
}

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.

$ ./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;
    }

    return 0;
}

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.

$ ./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.