Developing Apps on Qt, Part 2

4
6714
Qt time...

Qt time...

In the previous article in this series we went over the installation and some basic examples of Qt. In this article, we will learn how to use the Qt classes for basic data-types and lists.

Let’s begin with the basic data-type class, i.e., Qchar, which is based on 16-bit Unicode characters, which are 16-bit unsigned data. In C we have “char” single-byte variables limited to expressing 255 characters, but with 16 bits, many more characters can be used.

Some important member functions of this class are: isdigit(), isLetter(), isLower(), isUpper(), isSymbol(), toLower(), toUpper(), etc. To use this class, you need to include the QtCore library. Let’s look at an example.

As discussed in the previous article, create a new project in Qt Creator. From the list of project type options, I have chosen Qt Console Application, since I’m not using any graphic widgets. In the main.cpp file, enter the following code:

#include <QtCore/QCoreApplication>
#include <QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QChar ch;
    ch = 'M';
    if(ch.isLetter())
    {
        if(ch.isLower())
            qDebug() << "Ch is a Lower Letter";
        else
            qDebug() << "Ch is an Upper Letter";
    }
    qDebug() << sizeof(QChar);
    return a.exec();
}

Press Ctrl+r to build and execute the project. A pop-up window will display the following output:

Ch is an Upper Letter
2

To master the more than 20 member functions of the QChar class, write small programs to test them out, one by one.

The next important class is QString. Most times, project work requires dealing with strings. Qt has a very handy class called QString (a string of Unicode characters) whose base element is QChar.

Qt provides another option to store data in string-like form — QByteArray, which stores raw bytes. But to make your application support multiple languages, use QString for user-interface strings. The following example uses some of the important member functions:

#include <QtCore/QCoreApplication>
#include <QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString str("Linux");
    //QString str = "Linux";
    qDebug() << str.size() << str;
    str.append(" Kernel");
    qDebug() << str.size() << str;
    str.insert(5,"3.0");
    qDebug() << str.size() << str;
    if(str.startsWith("Linux"))
    {
        qDebug() << "The string starts with Linux";
    }
    int ret = QString::compare(str, "Linux3.0 Kernel", Qt::CaseInsensitive);
    if(!ret)
    {
        qDebug() << "Strings are equal";
    }
    return a.exec();
}

Running it yields the following output:

5 "Linux"
12 "Linux Kernel"
15 "Linux3.0 Kernel"
The string starts with Linux
Strings are equal

In the above code, we called a static function (compare) of QString, whose third argument is an enum Qt::CaseInsensitive. One important thing to remember is the difference between a NULL string and an empty string. Look at the following declarations:

QString str1;
QString str("");

In the first case, str1 is created with the default constructor, and is both null and empty. A null string is created when the QString object is created with the default constructor. In the second case, we have created the object with a string (""), so Qt will treat it as an empty string, but not a null string.

Working with lists

After the basic data classes, let’s work on container classes. To begin with, we have QList, a generic container class. Specify the type of item to hold in a QList with the general form:

QList<type> mylist;

Use int, QString, Qdate, etc, as the ‘type’. Let’s try some sample code:

#include <QtCore/QCoreApplication>
#include<QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QList<QString> mylist;
    mylist << "Two" << "Three";
    mylist.prepend("One");
    mylist.append("Four");
    for(int i=0; i< mylist.size(); i++)
    {
        qDebug() << mylist.at(i);
    }
    while(!mylist.isEmpty())
        mylist.takeFirst();
    qDebug() << "The list size = " << mylist.size();
    return a.exec();
}

The output of the above code follows:

"One"
"Two"
"Three"
"Four"
The list size =  0

In the above code, we used << to insert items in mylist. Member functions let us prepend and append items to the list. To access list elements, we use its index, with the member function at(index). To remove items from the head, we use takeFirst(); and to remove items from the tail, we use takeLast().

Iterator class

Instead of using an index, we can use iterators. The Qt iterator class is QListIterator. Let’s replace the for loop code in the above example with the following code:

    QListIterator<QString> it(mylist);
    while(it.hasNext())
        qDebug() << it.next();

Here, we created a QListIterator object to iterate over a QString list. We passed the QList object mylist to the constructor of QListIterator. This positions the iterator at the first element of mylist. The while loop keeps fetching and outputting items until the iterator reaches the end of the list.

The QList class provides STL (Standard Template Library) based iterators too. In terms of execution, they are faster (slightly) than the method described above. Here is a sample of code:

    QList<QString>::const_iterator it;
    for (it = mylist.constBegin(); it != mylist.constEnd(); it++)
        qDebug() << *it;

If you’re interested in this, you can find more details on iterators in the Qt documentation.

Let’s move on. An important class derived from QList handles QStrings in a proper manner. The class QStringList is a reimplementation of QList<QString>. I use this class when I need to split a string into sub-strings. Let’s try some sample code:

#include <QtCore/QCoreApplication>
#include<QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QStringList mylist;
    QString str("Linux Kernel 3.0");
    mylist = str.split(" ");
    for(int i=0; i<mylist.size(); i++)
        qDebug() << mylist.at(i);
    return a.exec();
}

Compile and run the program. The output will be as follows:

"Linux"
"Kernel"
"3.0"

We have created a QStringList object, then split the str string on each occurrence of a space, and assigned the resultant QStringList to mylist. We can then use indexes or iterators to access items.

I hope the concepts and practical examples shown here are sufficient to get started on working with simple data and lists. Let’s move ahead.

Key-value pairs

If you want to store items in key-value pairs, we have two options: QMap and QHash. From the programmer’s point of view, usage of both is similar, but they differ in how they store data. Once again, let’s understand the difference by examining some sample code:

#include <QtCore/QCoreApplication>
#include<QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QMap<QString,int> map;
    map["pidgin"] = 1;
    map["kopete"] = 4;
    map.insert("Empathy",3);
    QMapIterator<QString, int> it(map);
    while(it.hasNext())
    {
        it.next();
        qDebug() << it.key() << it.value();
    }
    if(map.contains("pidgin"))
    {
        qDebug() << map.value("pidgin");
    }
    return a.exec();
}

The output of this program would be:

"Empathy" 3
"kopete" 4
"pidgin" 1
1

Let’s dissect the code. First, we created a QMap object, and specified QString and int as the key-value pair. Then we inserted some keys and values in the map object. To access the items, we can use QMapIterator, which I think is simple enough, with no need for any  explanation. Items can be searched using the member function contains(), which returns true if any item exists with the given key.

In a similar way, you can try the QHash class, which provides a faster lookup than QMap, on your own.

Dynamic arrays

The last topic I want to discuss in this article is dynamic arrays. Qt has a container class called QVector, which is used to store data items in adjacent memory, as in C (e.g., int arr[10]). It provides index-based access to elements. Here is an example of how it is used:

#include <QtCore/QCoreApplication>
#include <QtCore>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QVector<int>  mVect;
    //QVector<int>  mVect(100);
    mVect << 20 << 10 << 30;
    mVect.insert(3,25);
    foreach(int n, mVect)
    {
        qDebug() << n;
    }
    qSort(mVect);
    qDebug() << "After Sorting";

    foreach(int n, mVect)
    {
        qDebug() << n;
    }
    return a.exec();
}

In the above code, we have created a QVector object mVect. Initially, its size is zero; if required, we can pass an initial size to the constructor. It’s no different from QList in terms of filling and accessing items. One important function we have used is qSort, which sorts the items of the container provided. Here is the output of the program:

20
10
30
25
After Sorting
10
20
25
30

I have tried to cover the most important non-GUI classes that manage data items, but there are so many other classes too, which you will find in the Qt documentation. I hope this article will help you get started with basic Qt programming.

In the next article, we will cover the signals and slots mechanism of the Qt framework. Until then, keep on experimenting!

4 COMMENTS

LEAVE A REPLY

Please enter your comment!
Please enter your name here