Функция currencyAt возвращает ключ (код валюты), который находится по указанному смещению в ассоциативном массиве валют. Мы используем итератор в стиле STL для поиска элемента и вызываем для него функцию key.
Как мы только что могли убедиться, нетрудно создавать модели, используемые только для чтения, и при определенном характере исходных данных в хорошо спроектированной
модели в принципе можно сэкономить память и увеличить быстродействие. В следующем примере приложения Города (Cities) также используется табличная модель, но на этот раз все данные вводятся пользователем.
Это приложение используется для хранения расстояний между любыми двумя городами. Как и в предыдущем примере, мы могли бы просто использовать табличный виджет QTableWidget и хранить один элемент для каждой пары городов. Однако пользовательская модель могла бы быть более эффективной, потому что расстояние от любого города А до любого другого города В не зависит от того, будем ли мы путешествовать от А до В или от В до А, поэтому элементы с одной стороны от главной диагонали получаются путем зеркального отражения другой.
Для сравнения пользовательской модели с простой таблицей предположим, что у нас имеется три города: А, В и С. Для обеспечения всех сочетаний нам пришлось бы хранить девять значений. В аккуратно спроектированной модели потребовалось бы только три элемента: (А, В), (A, С) и (В, С).
Рис. 10.12. Приложение Города.
Ниже показано, как мы настраиваем и используем модель:
Мы должны переопределить те же самые функции, которые мы переопределяли в предыдущем примере. Кроме того, для обеспечения возможности редактирования модели мы должны переопределить 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;
этой модели мы используем две структуры данных: 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 элемент для заданной строки и заданного столбца, возвращая расстояние для этой конкретной пары городов.