- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания QT 4 программирование GUI на С++ Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
05 }
Вызывающая программа может изменить набор валют, используя функцию setCurrencyMap(). Вызов QAbstractItemModel::reset() указывает любому представлению, что все данные в используемой модели недействительны; это вынуждает их запросить свежие данные для тех элементов, которые видны на экране.
01 QString CurrencyModel::currencyAt(int offset) const
02 {
03 return (currencyMap.begin() + offset).key();
04 }
Функция currencyAt() возвращает ключ (код валюты), который находится по указанному смещению в ассоциативном массиве валют. Мы используем итератор в стиле STL для поиска элемента и вызываем для него функцию key().
Как мы только что могли убедиться, нетрудно создавать модели, используемые только для чтения, и при определенном характере исходных данных в хорошо спроектированной модели в принципе можно сэкономить память и увеличить быстродействие. В следующем примере приложения Города (Cities) также используется табличная модель, но на этот раз все данные вводятся пользователем.
Это приложение используется для хранения расстояний между любыми двумя городами. Как и в предыдущем примере, мы могли бы просто использовать табличный виджет QTableWidget и хранить один элемент для каждой пары городов. Однако пользовательская модель могла бы быть более эффективной, потому что расстояние от любого города А до любого другого города В не зависит от того, будем ли мы путешествовать от А до В или от В до А, поэтому элементы с одной стороны от главной диагонали получаются путем зеркального отражения другой.
Для сравнения пользовательской модели с простой таблицей предположим, что у нас имеется три города: А, В и С. Для обеспечения всех сочетаний нам пришлось бы хранить девять значений. В аккуратно спроектированной модели потребовалось бы только три элемента: (А, В), (A, С) и (В, С).
Рис. 10.12. Приложение Города.
Ниже показано, как мы настраиваем и используем модель:
QStringList cities;
cities << "Arvika" << "Boden" << "Eskilstuna" << "Falun"
<< "Filipstad" << "Halmstad" << "Helsingborg" << "Karlstad"
<< "Kiruna" << "Kramfors" << "Motala" << "Sandviken"
<< "Skara" << "Stockholm" << "Sundsvall" << "Trelleborg";
CityModel CityModel;
cityModel.setCities(cities);
QTableView tableView;
tableView.setModel(&cityModel);
tableView.setAlternatingRowColors(true);
Мы должны переопределить те же самые функции, которые мы переопределяли в предыдущем примере. Кроме того, для обеспечения возможности редактирования модели мы должны переопределить setData() и flags(). Ниже приводится определение класса:
01 class CityModel : public QAbstractTableModel
02 {
03 Q_OBJECT
04 public:
05 CityModel(QObject *parent = 0);
06 void setCities(const QStringList &cityNames);
07 int rowCount(const QModelIndex &parent) const;
08 int columnCount(const QModelIndex &parent) const;
09 QVariant data(const QModelIndex &index, int role) const;
10 bool setData(const QModelIndex &index, const QVariant &value,
11 int role);
12 QVariant headerData(int section, Qt::Orientation orientation,
13 int role) const;
14 Qt::ItemFlags flags(const QModelIndex &index) const;
15 private:
16 int offsetOf(int row, int column) const;
17 QStringList cities;
18 QVector<int> distanсes;
19 };
В этой модели мы используем две структуры данных: cities типа QStringList для хранения названий городов, и distances типа QVector<int> для хранения расстояний между городами каждой уникальной пары.
01 CityModel::CityModel(QObject *parent)
02 : QAbstractTableModel(parent)
03 {
04 }
Конструктор передает параметр parent базовому классу и больше ничего не делает.
01 int CityModel::rowCount(const QModelIndex &
02 /* родительский элемент */) const
03 {
04 return cities.count();
05 }
06 int CityModel::columnCount(const QModelIndex &
07 /* родительский элемент */) const
08 {
09 return cities.count();
10 }
Поскольку мы имеем квадратную матрицу городов, количество строк и столбцов равно количеству городов в нашем списке.
01 QVariant CityModel::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 if (index.row() == index.column())
09 return 0;
10 int offset = offsetOf(index.row(), index.column());
11 return distances[offset];
12 }
13 return QVariant();
14 }
Функция data() аналогична той же функции в нашей модели CurrencyModel. Она возвращает 0, если строка и столбец имеют одинаковый номер, потому что в этом случае два города одинаковы; в противном случае она находит в векторе distances элемент для заданной строки и заданного столбца, возвращая расстояние для этой конкретной пары городов.
01 QVariant CityModel::headerData(int section,
02 Qt::Orientation /* ориентация */,
03 int role) const
04 {
05 if (role == Qt::DisplayRole)
06 return cities[section];
07 return QVariant();
08 }
Функция headerData() имеет простой вид, потому что наша таблица является квадратной матрицей, в которой строки и столбцы имеют идентичные заголовки. Мы просто возвращаем название города, расположенное с заданным смещением в списке строк cities.
01 bool CityModel::setData(const QModelIndex &index,
02 const QVariant &value, int role)
03 {
04 if (index.isValid() && index.row() != index.column()
05 && role == Qt::EditRole) {
06 int offset = offsetOf(index.row(), index.column());
07 distances[offset] = value.toInt();
08 QModelIndex transposedIndex = createIndex(
09 index.column(), index.row());
10 emit dataChanged(index, index);
11 emit dataChanged(transposedIndex, transposedIndex);
12 return true;
13 }
14 return false;
15 }
Функция setData() вызывается при редактировании элемента пользователем. Если индекс модели действителен, два города различны и модифицируемый элемент данных имеет ролевой атрибут Qt::EditRole, эта функция сохраняет введенное пользователем значение в векторе distances.
Функция createIndex() используется для формирования индекса модели. Она нужна для получения индекса модели элемента, который расположен по другую сторону от главной диагонали и который соответствует элементу с установленным значением, поскольку оба элемента должны показывать одинаковые данные. Функция createIndex() принимает сначала строку и затем столбец; здесь мы передаем параметры в обратном порядке, чтобы получить индекс модели элемента, расположенного по другую строну диагонали напротив элемента, определенного индексом index.
Мы генерируем сигнал dataChanged() с указанием индекса модели элемента, который изменился. Эта функция принимает два индекса модели, поскольку возможна ситуация, когда изменения относятся к некоторой прямоугольной области, охватывающей несколько строк и столбцов, поэтому передаются индекс верхнего левого угла и индекс нижнего правого угла этой области. Генерируем также сигнал dataChanged() для индекса противоположного элемента, чтобы представление обновило его отображение на экране. Наконец, мы возвращаем true или false, указывая на успешность или неуспешность редактирования.
01 Qt::ItemFiags CityModel::flags(const QModelIndex &index) const
02 {
03 Qt::ItemFlags flags = QAbstractItemModel::flags(index);
04 if (index.row() != index.column())
05 flags |= Qt::ItemIsEditable;
06 return flags;
07 }
Функция flags() используется моделью для того, чтобы можно было сообщить о допустимых действиях с элементом (например, допускает ли он редактирование). По умолчанию эта функция для модели QAbstractTableModel возвращает Qt::ItemIsSelectable | Qt::ItemIsEnabled. Мы добавляем флажок Qt::ItemIsEditable для всех элементов, кроме расположенных по диагонали (которые всегда равны 0).
01 void CityModel::setCities(const QStringList &cityNames)
02 {
03 cities = cityNames;
04 distances.resize(cities.count() * (cities.count() - 1) / 2);
05 distances.fill(0);
06 reset();
07 }
Если задан новый список городов, мы устанавливаем закрытую переменную типа QStringList на новый список, изменяем размеры и очищаем вектор расстояний, а затем вызываем функцию QAbstractItemModel::reset(), чтобы уведомить все представления о необходимости обновления всех видимых элементов.