- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 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() указывает любому представлению, что все данные в используемой модели недействительны; это вынуждает их запросить свежие данные для тех элементов, которые видны на экране.