Компания ALT Linux
Опубликован: 07.03.2015 | Доступ: свободный | Студентов: 2134 / 486 | Длительность: 24:14:00
Лекция 12:

Структура проекта. Основные типы

12.5 Контейнерные классы в Qt

Список строк QStringList, который мы рассматривали, является представителем семейства контейнерных классов Qt, которые являются аналогом контейнеров STL. Но в то же время они имеют свои собственные различия в реализации и возможностях. Мы же будем в дальнейшем использовать в наших примерах исключительно контейнеры Qt.

Простейшим контейнерным классом является QList. QListсписок общего назначения. Для добавления элементов в начало и в конец списка используют методы prepend() и append(). Также можно добавить несколько элементов за раз используя потоковые операторы. Например:

#include <QList>
...
QList<QString> lList;
QString lStr1 ( " string 1 " );
QString lStr2 ( " string 2 " );
lList << lStr1 << lStr2; //Добавляем несколько элементов за раз
lList.prepend ( lStr1 ); //Добавляем элемент в начало (повторно)
lList.append ( " string 3 " ); //Добавляем в конец списка
lList << " string 4 "; //То же, что и lList.append (" string 4 ");

Последние две строки возможны за счёт неявного преобразования char* в QString. Класс QStringList, которого мы коснулись в примерах предыдущего раздела посвящённого текстовым строкам, наследует от QList<QString> и реализует ряд дополнительных методов для работы со строками в списке.

Для доступа к элементам используют метод at(), который принимает индекс элемента в списке в качестве аргумента. Количество элементов в списке возвращают методы size() и count().

qDebug ( ) << lList.first ( );
qDebug ( ) << lList.last ( );
if ( lList.size ( ) >3) qDebug ( ) << lList.at ( 3 );

Также стоит отметить два других важных разновидности контейнеров: хэш (QHash) и словарь (QMap). Хэш — контейнер, в котором элементы добавляют парами (ключ-значение). Значение в хэше находят по ключу, а для поиска используют хэш-функцию, которая преобразует ключ в значение. В словаре элементы также добавляют парами ключ-значение, но значение сортируют по ключу. Для доступа к значению, используют метод value(), который принимает два параметра: ключ и значение по умолчанию, которое метод вернёт, если значение не будет найдено. Например:

#include <QMap>
...
QMap<QString, QString> lSurnameByName;
lSurnameByName.insert ( " Bill ", " Hunter " );
lSurnameByName.insert ( " Marry ", " Lee " );
//Поиск значения по ключу
qDebug ( ) << " Bill " << lSurnameByName.value ( " Bill " );
qDebug ( ) << " Marry " << lSurnameByName.value ( " Marry ", " Doe " );
//Прибавляем другое значение с уже существующим ключом
lSurnameByName.insert ( " Marry ", " Hunter " );
qDebug ( ) << " Marry " << lSurnameByName.value ( " Marry " );
//Ключи не существуют — вывод значений по умолчанию
qDebug ( ) << " James " << lSurnameByName.value ( " James " );
qDebug ( ) << " John " << lSurnameByName.value ( " John ", " Doe " );

После выполнения получим вывод:

Bill "Hunter"
Marry "Lee"
Marry "Hunter"
James ""
John "Doe"

Обратите внимание: после того, как мы добавили ещё одно значение с тем же ключом (Marry), предыдущее значение было перезаписано новым значением. Для того, чтобы добавить несколько значений с одним и тем же ключом можно воспользоваться методом insertMulti().

#include <QHash>
...
QHash<QString, QString> lClassificationHash;
//Добавляем несколько значений с одинаковыми ключами
lClassificationHash.insertMulti ( " fruits ", " apple " );
lClassificationHash.insertMulti ( " fruits ", " orange " );
lClassificationHash.insertMulti ( " vegetables ", " potato " );
lClassificationHash.insertMulti ( " vegetables ", " cabbage " );
lClassificationHash.insertMulti ( " vegetables ", " tomato " );
qDebug ( )<< lClassificationHash.value ( " fruits " ); //Вывод одного значения с ключом
qDebug ( )<< lClassificationHash.values ( " fruits " ); //Вывод значений с ключом
qDebug ( )<< lClassificationHash.values ( " vegetables " );

Получим следующий вывод в консоль:

"orange"
("orange", "apple")
("tomato", "cabbage", "potato")

Для итерации по списку можно воспользоваться макросом foreach. Также можно воспользоваться итератором в стиле Java. Например:

QList<int> lList; //Создаём список целых чисел
lList.append ( 3 ); //Добавляем элементы
lList.append ( 6 );
lList.append ( 9 );
QListIterator <int> lIt ( lList ); //Создаём итератор для списка
while ( lIt.hasNext ( ) ) //Пока следующий элемент существует
{
	qDebug ( ) << lIt.next ( ); //...вывести следующий элемент
}

Другой пример — итерация в обратном направлении. На этот раз используем хеш.

QHash<QString, int> lNumberByName;
lNumberByName.insert ( " twelve ", 12 );
lNumberByName.insert ( " thirty three ", 33 );
lNumberByName.insert ( " one hundred an twenty five ", 125 );
QHash It erator<QString, int> lHashIterator ( lNumberByName );
lHashIterator.toBack ( ); //Перейти к концу контейнера — итератор указывает после
//последнего элемента
while ( lHashIterator.hasPrevious ( ) )
{
	lHashIterator.previous ( ); //Переходим к предыдущемму элементу
	//Выводим ключ и значение
	qDebug ( ) << lHashIterator.key ( )<< " - " << lHashIterator.value ( );
}

Следующий пример — с итератором в стиле STL.

QHash<QString, int >::const_iterator lStlLikeIterator;
for ( lStlLikeIterator = lNumberByName.begin ( );
lStlLikeIterator != lNumberByName.end ( );
lStlLikeIterator ++)
{
qDebug ( ) << lStlLikeIterator.key ( )<< " - "
//Тоже самое, что и * lStlLikeIterator
<< lStlLikeIterator.value ( );
}
Таблица 12.3. приведены разновидности контейнеров Qt.
Переменная Описание особенностей
QList Список общего назначения для использования в большинстве ситуаций, которые возникают при разработке. Имеет оптимальное быстродействие в большинстве случаев.
QLinkedList Реализует связный список в Qt. Отсутствует операция доступа по индексу элемента (такая как at(int pos)).
QVector Реализует вектор элементов в Qt.
QStack Реализует стек. Стек размещает элементы по принципу LIFO (Last In, First Out) — элемент, добавленный первым будет последним элементом в стеке.
QQueue Реализует очередь. Очередь размещает элементы по принципу FIFO (First In, First Out) — элемент, добавленный первым, будет первым элементом в очереди
QSet Множество элементов. Гарантирует, что все элементы будут уникальными.
QMap Контейнерный класс для словаря. Элементы добавляют парами: ключ-значение. Словарь всегда сортирует элементы по ключу. Позволяет найти элемент по ключу.
QMultiMap Контейнерный класс словаря создан для удобной работы с тем, чтобы каждому ключу соответствовало несколько значений. Метод insert() не заменяет значение ключа, если ключ уже существует, а добавляет новую пару ключ-значение.
QHash Контейнерный класс для хеша. Элементы добавляют парами: ключ — значение. Элементы хранятся в хеше в произвольном порядке. Позволяет выполнять очень быстрый поиск элемента по ключу.
QMultiHash Контейнерный класс хеша, создан для удобной работы с тем, чтобы каждому ключу соответствовало несколько значений. Метод insert() не заменяет значение ключа, если ключ уже существует, а добавляет новую пару ключ-значение.
Сергей Радыгин
Сергей Радыгин

Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке?

Тип приложения - не Qt,

Qt Creator 4.5.0 основан на Qt 5.10.0. Win7.

 

Юрий Герко
Юрий Герко

Кому удалось собрать пример из раздела 13.2 Компоновка (Layouts)? Если создавать проект по изложенному алгоритму, автоматически не создается  файл mainwindow.cpp. Если создавать этот файл вручную и добавлять в проект, сборка не получается - компилятор сообщает об отсутствии класса MainWindow. Как правильно выполнить пример?