Структура InterviewКлассы Interview обеспечивают структуру модель/представление для приложений, базирующихся на этом известном шаблоне проектирования модель-представление-контроллер (Model-View-Controller). В данном документе мы опишем архитектуру модель/представление Qt, представим несколько примеров и продемонстрируем усовершенствования классов представления элементов по сравнению с Qt 3. Обзор архитектуры модель/представлениеАрхитектура модель/представление - это разновидность шаблона проектирования модель-представление-контроллер (Model-View-Controller, MVC), пришедшей из Smalltalk, часто используемый при создании пользовательских интерфейсов. В архитектуре модель/представление представление и структура данных объединены. Это все еще отделяет способ хранения данных от способа их представления пользователю, но обеспечивает простую структуру, основанную на тех же принципах. Данное разделение дает возможность показать пользователю одни и те же данных в различных представлениях и реализовать новые типы представлений без изменения базовой структуры данных. Данные, вводимые пользователем, обрабатываются делегатами. Преимущество этого подхода состоит в том, что для каждый используемого типа данных он позволяет настраивать подходящее отображение и редактирование отдельных элементов данных.
Классы модель/представлениеНа фундаментальном уровне классы Interview определяют интерфейсы и общие функциональные возможности для моделей, представлений и делегатов. Все реализованные компоненты являются подклассами QAbstractItemModel, QAbstractItemView или QAbstractItemDelegate. Использование общего API обеспечивает возможность взаимодействия между компонентами. Interview предоставляет готовые для использования реализации представлений для виджетов таблицы, дерева и списка: QTableView, QTreeView и QListView. Эти стандартные представления, подходящие для отображения наиболее распространенных типов структур информации, используемых в приложениях, могут использоваться с готовыми моделями поставляемыми с Qt:
Обе предоставляемые специализированные абстрактные модели могут быть расширены и послужить базовыми классами (смотрите примеры в Программирование модель/представление):
Операции над элементами, например фильтрация и сортировка, обрабатываются моделями-посредниками, которые позволяют отображать обработанные данные без необходимости копировать или изменять данные, полученные от модели-источника. Interview предоставляет класс QSortFilterProxyModel, позволяющий отсортировать и отфильтровать элементы данных из модели-источника до того, как они будут переданы представлению. Разработчики, предпочитающие обычные виджеты списка, дерева и таблицы, могут найти полезными QListWidget, QTreeWidget и QTableWidget. Они предоставляют облегченный интерфейс для представлений не требующий знания основ архитектуры модель/представление. Для получения детальных сведений об использовании классов модель/представление, смотрите документ Программирование модель/представление. Для получения информации о моделях баз данных Qt 4, также смотрите документ GUI работы с базами данных. Примеры кодаЧтобы проиллюстрировать использование классов модель/представление, мы представляем два примера, демонстрирующих различные аспекты использования архитектуры модель/представление. Разделение модели между представлениями элементовВ данном примере мы показываем содержимое модели, используя два различных представления и разделяем между ними выбор элементов. Мы будем использовать модель QFileSystemModel, поставляемую с Qt, потому что она практически не требует настройки и предоставляет существующие данные для представлений. Функция main() данного примера демонстрирует все принципы, применяемые для настройки модели и двух представлений. Мы также разделяем выбор между двумя представлениями: int main(int argc, char *argv[]) { QApplication app(argc, argv); QSplitter *splitter = new QSplitter; QFileSystemModel *model = new QFileSystemModel; model->setRootPath(QDir::currentPath()); QTreeView *tree = new QTreeView(splitter); tree->setModel(model); tree->setRootIndex(model->index(QDir::currentPath())); QListView *list = new QListView(splitter); list->setModel(model); list->setRootIndex(model->index(QDir::currentPath())); QItemSelectionModel *selection = new QItemSelectionModel(model); tree->setSelectionModel(selection); list->setSelectionModel(selection); splitter->setWindowTitle("Two views onto the same file system model"); splitter->show(); return app.exec(); } В приведенной функции мы создаем модель каталога, чтобы показать содержимое каталога по умолчанию. Создаются два представления и для работы с ними предоставляется модель. По умолчанию, каждое представление создает и отображает свой собственный выбор элементов модели, поэтому мы явно создаем новый выбор, который разделяется между представлением дерева и представлением списка. В результате, изменение выбора в одном из этих представлений автоматически заставляет измениться выбор в другом представлении. Архитектура модель/представление позволяет нам заменить в данном примере QFileSystemModel на совершенно другую модель, получающую информацию от удаленного сервера или из базы данных. Создание собственной моделиВ этом примере мы покажем элементы данных, полученные из пользовательской модели списка, используя стандартные предоставления. Собственная модель является подклассом QAbstractListModel и предоставляет реализацию основного набора функций. Полное объявление нашей модели: class StringListModel : public QAbstractListModel { Q_OBJECT public: StringListModel(const QStringList &strings, QObject *parent = 0) : QAbstractListModel(parent), stringList(strings) {} int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; private: QStringList stringList; }; При создании модель принимает список строк и по требованию передает их в представления. Так как это простая модель только для чтения, мы должны реализовать лишь несколько функций. Базовой структурой данных, используемой для хранения строк, является QStringList. Так как модель отображает каждый элемент списка в отдельную строку модели, функция rowCount() очень проста: int StringListModel::rowCount(const QModelIndex &parent) const { return stringList.count(); } Функция data() возвращает элемент данных для каждого модельного индекса, предоставляемого представлением: QVariant StringListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= stringList.size()) return QVariant(); if (role == Qt::DisplayRole || role == Qt::EditRole) return stringList.at(index.row()); else return QVariant(); } Функция data() возвращает значение типа QVariant, содержащее информацию, на которую ссылается модельный индекс. Элементы данных возвращаются представлению только если прошли все проверки переданного индекса; например, если представление задает неверный модельный индекс, модель указывает на это возвращая недействительный QVariant. Вывод вертикальных или горизонтальных заголовков осуществляется функцией headerData(). В данной модели возвращаемое значение для этих элементов - это номер строки или столбца, находящегося в заголовке: QVariant StringListModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) return QString("Column %1").arg(section); else return QString("Row %1").arg(section); } В данном примере мы приведем только часть функции main(): QStringList numbers; numbers << "One" << "Two" << "Three" << "Four" << "Five"; QAbstractItemModel *model = new StringListModel(numbers); ... QListView *view = new QListView; view->setWindowTitle("View onto a string list model"); view->setModel(model); Мы создали список строк для использования с моделью и передаем его в модель при ее создании. Информация в списке строк сделана доступной представлению через нашу модель. Этот пример показывает, как легко заполнять представления данными из простой модели. Стандартные модели и представления, разработанные для Qt 4, сделают этот процесс еще более легким, а вспомогательные виджеты обеспечат поддержку классического подхода на основе элементов данных. Что изменилось по сравнению с Qt 3?Таблицы и классы представления элементов в Qt 3 реализовывались виджетами, которые и хранили данные, и представляли их пользователю. Эти классы проектировались легкими в работе и согласованными, но иногда их трудно было настраивать и расширять. Эквивалентные классы в Qt 4 спроектированы так, чтобы быть расширяемыми при сохранении удобства в работе; использование архитектуры модель/представление гарантирует, что они стали более последовательны, чем их предшественники. Подведем итоги о предоставляемых классах представлений:
Так как модель берет на себя ответственность за предоставление элементов данных, а представление - за их отображение пользователю, нам не нужны классы элементов для отображения отдельных элементов. Делегаты обрабатывают отрисовку и редактирование данных, полученных от модели. Qt продолжает предоставлять множество классических виджетов представлений элементов со знакомыми, основанными на элементах интерфейсами, которые не базируются на классах совместимости:
Каждый из вспомогательных классов имеет связанный с ним класс элементов: QListWidgetItem, QTreeWidgetItem и QTableWidgetItem являются эквивалентами в Qt 4 для QListBoxItem, QListViewItem и QTableItem из Qt 3 соответственно. Элементы архитектуры модель/представление предусматривают и использование "как есть", и могут быть основой разработок программистов. Хотя такой подход может показаться чересчур сложным для простых приложений, он поощряет повторное использование компонентов. |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |