Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Разработка приложений с использованием Qt, часть 2

Оригинал: Developing Apps on Qt, Part 2
Автор: Manoj Kumar
Дата публикации: 29 февраля 2012
Перевод: А.Панин
Дата публикации перевода: 6 ноября 2012 г.

В предыдущей статье серии мы кратко рассмотрели установку Qt и несколько простейших примеров программ с использованием этого фреймворка. В данной статье мы научимся использовать классы Qt для работы с простейшими типами данных и списками.

Давайте начнем с простейшего класса для работы с данными, т.е. с Qchar, который работает с 16-битными символами Unicode, представленными 16-битными беззнаковыми целыми значениями. В C существует тип "char" для работы с однобайтовыми значениями, для которых существует ограничение в 255 различных символов, поэтому при значениях размером в 16 бит возможно использование большего количества различных символов.

Некоторыми важными функциями этого класса являются: isdigit(), isLetter(), isLower(), isUpper(), isSymbol(), toLower(), toUpper(), и.т.д. Для использования этого класса необходимо подключить заголовочный файл QtCore. Давайте рассмотрим пример.

На основе описания из предыдущей статьи серии, создайте новый проект в Qt Creator. Я выбрал Консольное приложение Qt (Qt Console Application) из списка возможных типов проекта, поскольку не планирую использовать элементы графического интерфейса. Сохраните следующий код в файле main.cpp:
#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();
}
Нажмите Ctrl+r для сборки и запуска проекта. Во всплывающем окне можно будет увидеть следующий вывод программы:
Ch is an Upper Letter
2

Для того, чтобы разобраться в работе более 20 функций класса QChar, разработайте аналогичные небольшие программы и протестируйте эти функции по очереди.

Следующим важным классом является QString. В большинстве случаев при работе над проектом приходится сталкиваться с необходимостью обработки строк. В составе Qt есть очень полезный класс под названием QString (строки состоят из символов Unicode), базовым элементом которого являются объекты QChar.

Qt предоставляет и другой вариант хранения данных в форме строк - QByteArray, который хранит просто байтовое представление данных. Но для того, чтобы сделать возможной поддержку различных языков приложением, следует использовать класс QString для строк, используемых в пользовательском интерфейсе. В следующем примере кода используется ряд важных функций:
#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();
}
После запуска следует вывод:
5 "Linux"
12 "Linux Kernel"
15 "Linux3.0 Kernel"
The string starts with Linux
Strings are equal
В вышеприведенном коде мы использовали статическую функцию compare класса QString, третьим аргументом которой является энумератор Qt::CaseInsensitive. Важной вещью, о которой необходимо помнить, является различие между строкой со значением NULL и пустой строкой. Посмотрите на следующие объявления:
QString str1;
QString str("");

В первом случае объект str1 создан при помощи стандартного конструктора и строка является одновременно и пустой строкой и строкой со значением NULL. Строка со значением NULL создается при создании экземпляра класса QString при помощи стандартного конструктора. Во втором случае при создании объекта мы передали строку инициализации (""), поэтому Qt будет рассматривать объект как пустую строку, а не строку со значением NULL.

Работа со списками

После рассмотрения классов для работы с базовыми типами данных, давайте рассмотрим контейнерные классы. Начнем с того, что в нашем распоряжении есть QList, являющийся универсальным контейнерным классом. Задавайте тип хранимых при помощи QList данных в следующей обобщенной форме:
QList<type> mylist;
Можете использовать int, QString, Qdate, и.т.д. вместо "type". Давайте рассмотрим следующий код в качестве примера:
#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();
}
После исполнения получен вывод, приведенный ниже:
"One"
"Two"
"Three"
"Four"
The list size = 0

В коде выше мы использовали оператор для добавления элементов в список mylist. Функции класса позволяют нам добавлять элементы в начало и в конец списка. Для доступа к элементам списка мы использовали порядковый номер элемента, передавая его в качестве аргумента функции at(index). Для удаления элементов с начала списка мы использовали функцию takeFirst(); а для удаления элементов с конца списка мы использовали takeLast().

Класс итератора

Вместо доступа к элементам списка по порядковому номеру, мы можем использовать итераторы. Класс итератора в Qt носит название QListIterator. Давайте заменим цикл for в коде выше на следующий код:
	QListIterator<QString> it(mylist);
	while(it.hasNext())
		qDebug() < it.next();

Здесь мы создаем объект QListIterator для перечисления элементов списка, хранящего объекты QString. Мы передаем объект mylist типа QList конструктору класса QListIterator. Это позволяет установить итератор на первый элемент списка mylist. В цикле while происходит получение и вывод значений элементов до того момента, как итератор достигает конца списка.

Класс QList также предоставляет возможность использовать итераторы, основанные на стандартной библиотеке шаблонов (Standard Template Library). Если судить по скорости работы, они быстрее (незначительно), чем метод, описанный выше. А вот и пример кода:
	QList<QString>::const_iterator it;
	for (it = mylist.constBegin(); it != mylist.constEnd(); it++)
		qDebug() < *it;

Если вас заинтересовала эта тема, вы можете найти больше подробностей об итераторах в документации Qt.

Двигаемся дальше. Важный класс, являющийся потомком QList, позволяет работать с объектами типа QString надлежащим образом. Класс QStringList является вариантом реализации QList<QString>. Я использую этот класс в тех случаях, когда хочу разделить строку на подстроки. Давайте рассмотрим пример исходного кода:
#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();
}
Скомпилируйте и запустите программу. Вывод будет аналогичен приведенному ниже:
"Linux"
"Kernel"
"3.0"

Мы создали объект типа QStringList, затем разделили строку str на составляющие на основании наличия пробелов и присвоили результирующее значение переменной mylist типа QStringList. После этого мы можем использовать порядковые номера или итераторы для доступа к элементам списка.

Надеюсь, что описания концепций работы и практические примеры, приведенные выше, достаточны для начала работы с базовыми типами данных и списками. Давайте двигаться дальше.

Пары ключ-значение

Если вы хотите хранить элементы в виде пар ключ-значение, у вас есть два варианта классов: QMap и QHash. С точки зрения программиста, классы используются аналогично, тем не менее, они отличаются тем, как хранят данные. Еще раз, давайте рассмотрим различия на примере исходного кода:
#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();
}
Вывод этой программы должен быть следующим:
"Empathy" 3
"kopete" 4
"pidgin" 1
1

Давайте проанализируем код. Сначала мы создали объект QMap и задали в качестве типов данных пары ключ-значение QString и int соответственно. После этого мы добавили несколько ключей и значений для хранения. Для доступа к элементам мы можем использовать итератор QMapIterator, который прост в использовании, и, на мой взгляд, не нуждается в описании. Поиск элементов осуществляется при помощи функции contains(), которая возвращает true в том случае, если существует элемент с заданным ключом.

Аналогичным образом вы можете использовать класс QHash, который позволяет повысить скорость доступа к элементам по сравнению с QMap.

Динамические массивы

Последней темой, которую я хотел бы обсудить в данной статье, являются динамические массивы. В Qt присутствует контейнерный класс, называемый QVector, который используется для хранения элементов в смежных областях памяти, как и в C (int arr[10]). Он позволяет осуществлять доступ к элементам на основе индексов. Пример того, как этот класс может быть использован:
#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();
}
В коде выше мы создали объект QVector mVect. Изначально размер массива равен нулю; в случае необходимости, мы можем передать начальный размер конструктору. Нет никаких отличий от QList в плане добавления элементов и доступа к ним. Одной из важных функций, использованной нами, является qSort, позволяющая отсортировать элементы массива. Ниже представлен вывод программы:
20
10
30
25
After Sorting
10
20
25
30

Я попытался затронуть самые важные классы, не относящиеся к графическому интерфейсу, которые позволяют осуществлять работу с различными типами данных, но существует и множество других классов, описание которых вы можете найти в документации Qt. Надеюсь, что эта статья поможет вам начать заниматься программированием с использованием Qt.

В следующей статье мы рассмотрим механизм сигналов и слотов в фреймворке Qt. А до этого времени продолжайте экспериментировать самостоятельно!