- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
QT 4: программирование GUI на С++ - Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
Реализация пользовательских моделей
Заранее определенные в Qt модели предлагают удобные средства обработки и просмотра данных. Однако некоторые источники данных не могут эффективно использоваться для этих моделей, и в этих случаях необходимо создавать пользовательские модели, оптимизированные на применение таких источников данных.
Прежде чем перейти к созданию пользовательских моделей, давайте рассмотрим ключевые концепции архитектуры Qt модель/представление. В модели каждый элемент имеет индекс модели и набор атрибутов, называемых ролями, которые могут принимать произвольные значения. Ранее в данной главе мы видели, что наиболее распространенными ролями являются Qt::DisplayRole и Qt::EditRole. Другие роли используются для вспомогательных данных (например, Qt::ToolTipRole, Qt::StatusTipRole и Qt::WhatsThisRole) или для управления основными атрибутами отображения (например, Qt::FontRole, Qt::TextAlignmentRole, Qt::TextColorRole и Qt::BackgroundColorRole).
Рис. 10.9. Схематическое представление моделей Qt.
В модели списка можно пользоваться только одним индексным компонентом — номером строки, получить доступ к которому можно с помощью функции QModelIndex::row(). В модели таблицы используется два индексных компонента — номер строки и номер столбца, получить доступ к которым можно с помощью функции QModelIndex::row() и QModelIndex::column(). В моделях списка и таблицы родительский элемент всех остальных элементов является корневым элементом, который представдяется недействительным индексом модели QModelIndex. Представленные в данном разделе первые два примера показывают, как можно реализовать пользовательские модели таблиц.
Модель дерева подобна модели таблицы при следующих отличиях. Как и в модели таблицы, родительский элемент элементов верхнего уровня является корневым (имеет недействительный QModelIndex), однако родительский элемент любого другого элемента занимает другое место в иерархии элементов. Доступ к родительским элементам можно получить при помощи функции QModelIndex::parent(). Каждый элемент имеет свои ролевые данные и может иметь или не иметь дочерние элементы, каждый из которых является таким же элементом. Поскольку любой элемент может иметь дочерние элементы, такую структуру данных можно определить рекурсивно (в виде дерева), что будет продемонстрировано в последнем примере данного раздела.
В первом примере этого раздела представлена модель таблицы, используемой только для чтения; она показывает курсы различных валют относительно друг друга.
Рис. 10.10. Приложение Курсы валют (Currencies).
Это приложение можно было бы реализовать при помощи простой таблицы, но мы хотим использовать пользовательскую модель, чтобы можно было воспользоваться определенными свойствами данных для обеспечения минимального расхода памяти. Если бы мы хранили в таблице 162 валюты, действующие в настоящее время, нам бы потребовалось хранить 162 × 162 = 26 244 значения; в представленной ниже пользовательской модели необходимо хранить только 162 значения (значение каждой валюты относительно доллара США).
Класс CurrencyModel будет использоваться совместно со стандартным табличным представлением QTableView. Модель CurrencyModel пополняется элементами QMap<QString, double>; ключ каждого элемента представляет собой код валюты, а значение — курс валюты в долларах США. Ниже приводится фрагмент программного кода, показывающий, как пополняется ассоциативный массив QMap и как используется модель:
QMap<QString, double> currencyMap;
currencyMap.insert("AUD", 1.3259);
currencyMap.insert("CHF", 1.2970);
…
currencyMap.insert("SGD", 1.6901);
currencyMap.insert("USD", 1.0000);
CurrencyModel currencyModel;
currencyModel.setCurrencyMap(currencyMap);
QTableView tableView;
tableView.setModel(¤cyModel);
tableView.setAlternatingRowColors(true);
Теперь мы можем перейти к реализации модели, начиная с ее заголовка:
01 class CurrencyModel : public QAbstractTableModel
02 {
03 public:
04 CurrencyModel(QObject *parent = 0);
05 void setCurrencyMap(const QMap<QString, double> &map);
06 int rowCount(const QModelIndex &parent) const;
07 int columnCount(const QModelIndex &parent) const;
08 QVariant data(const QModelIndex &index, int role) const;
09 QVariant headerData(int section, Qt::Orientation orientation,
10 int role) const;
11 private:
12 QString currencyAt(int offset) const;
13 QMap<QString, double> currencyMap;
14 };
Для нашей модели мы использовали подкласс QAbstractTableModel, поскольку он лучше всего подходит к нашему источнику данных. Qt содержит несколько базовых классов моделей, включая QAbstractListModel, QAbstractTableModel и QAbstractItemModel. Класс QAbstractItemModel используется для поддержки разнообразных моделей, в том числе тех, которые построены на рекурсивных структурах данных, а классы QAbstractListModel и QAbstractTableModel удобно применять для одномерных и двумерных наборов данных.
Рис. 10.11. Дерево наследования для абстрактных классов моделей.
Для модели таблицы, используемой только для чтения, мы должны переопределить три функции: rowCount(), columnCount() и data(). В данном случае мы также переопределили функцию headerData() и обеспечили функцию инициализации данных (setCurrencyMap()).
01 CurrencyModel::CurrencyModel(QObject*parent)
02 : QAbstractTableModel(parent)
03 {
04 }
В конструкторе нам ничего не надо делать, кроме передачи базовому классу parent в качестве параметра.
01 int CurrencyModel::rowCount(const QModelIndex &
02 /* родительский элемент */) const
03 {
04 return currencyMap.count();
05 }
06 int CurrencyModel::columnCount(const QModelIndex &
07 /* родительский элемент */) const
08 {
09 return currencyMap.count();
10 }
В этой табличной модели счетчики строк и столбцов представляют собой номера валют в ассоциативном массиве валют. Параметр parent не имеет смысла в модели таблицы; он здесь указан, потому что rowCount() и columnCount() наследуются от более обобщенного базового класса QAbstractItemModel, поддерживающего иерархические структуры.
01 QVariant CurrencyModel::data(const QModelIndex &index, int role) const
02 {
03 if (!index.IsValid())
04 return QVariant();
05 if (role == Qt::TextAlignmentRole) {
06 return int(Qt::AlignRight | Qt::AlignVCenter);
07 } else if (role == Qt::DisplayRole) {
08 QString rowCurrency = currencyAt(index.row());
09 QString columnCurrency = currencyAt(index.column());
10 if (currencyMap.value(rowCurrency) == 0.0)
11 return "####";
12 double amount = currencyMap.value(columnCurrency)
13 / currencyMap.value(rowCurrency);
14 return QString("%1").arg(amount, 0, 'f', 4);
15 }
16 return QVariant();
17 }
Функция data() возвращает значение любой одной роли элемента. Элемент определяется индексом QModelIndex. В модели таблицы представляют интерес такие компоненты QModelIndex, как номер строки и номер столбца, получить доступ к которым можно с помощью функций row() и column().
Если используется роль Qt::TextAlignmentRole, мы возвращаем значение, подходящее для выравнивания чисел. Если используется роль Qt::DisplayRole, мы находим значение каждой валюты и вычисляем курс обмена.
Мы могли бы возвращать рассчитанное значение типа double, но тогда нам пришлось бы контролировать количество позиций после десятичной точки при отображении числа (если мы не используем пользовательский делегат). Вместо этого мы возвращаем значение в виде строки, отформатированной нужным нам образом.
01 QVariant CurrencyModel::headerData(int section,
02 Qt::Orientation /* ориентация */, int role) const
03 {
04 if (role != Qt::DisplayRole)
05 return QVariant();
06 return currencyAt(section);
07 }
Функция headerData() вызывается представлением для пополнения своих горизонтальных и вертикальных заголовков. Параметр section содержит номер строки или столбца (в зависимости от ориентации). Поскольку строки и столбцы содержат одинаковые коды валют, нам не надо заботиться об ориентации, а просто вернуть код валюты для заданного значения section.
01 void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
02 {
03 currencyMap = map;
04 reset();
05 }
Вызывающая программа может изменить набор валют, используя функцию setCurrencyMap(). Вызов QAbstractItemModel::reset() указывает любому представлению, что все данные в используемой модели недействительны; это вынуждает их запросить свежие данные для тех элементов, которые видны на экране.

