Для организации сложных комплексных приложений фреймворк Qt применяет архутектуру View/Model (Представление/Модель), которая является модификацией паттерна MVC.
Традиционный паттерн MVC или Model-View-Controller (Модель-Представление-Контроллер) состоит из трех элементов:
Модель: описывает используемые в приложении данные, а также логику, которая связана с данными, например, логику валидации данных или другую бизнес-логику.
Представление: компонент, который определяет визуальный интерфейс
Контроллер: компонент для обработки пользовательского ввода. Через контроллер идет взаимодействие пользователя с приложением
В общем случае пользователь обращается к приложению, и его запрос обрабатывает контроллер и возвращает пользователю представление в виде некоторого визуального интерфейса. Если необходимо обращение к модели, например, для получения данных или некоторых операций над данными, контроллер обращается к модели, а результат обращения к модели встраивается в приложение (например, данные выводятся в таблицу и т.д.). В итоге после обращения к приложению пользователь получает некоторый визуальный интерфейс. Существуют различные разночтения и реализации этого паттерна, которые могут немного отличаться от прежложенной схемы, например, иногда не контроллер генерирует представление, а модель и ряд других отличий.
В Qt представление и контроллер объединены, в результате чего образуется архитектура Model/View (модель/представление). Такая архитектура обеспечивает более простую структуру, и при этом механизм хранения данных и работы с ними по-прежнему отделен их представления пользователю. Такое разделение позволяет отображать одни и те же данные в нескольких разных представлениях и реализовывать новые типы представлений без изменения базовых структур данных. Для обеспечения гибкой обработки пользовательского ввода фреймворк Qt вводит концепцию делегата. Преимущество наличия делегата в этой структуре заключается в том, что он позволяет настраивать способ отображения и редактирования элементов данных.
В итоге все компоненты в этой архитектуре можно разделить на три группы, описанные выше: модели, представления и делегаты. Весь процесс работы приложения в этой архитектуре выглядит следующим образом. Модель взаимодействует с источником данных, обеспечивая интерфейс для других компонентов архитектуры. Представление через индексы модели может взаимодействовать с данными. В частности, используя индексы модели, представление через модель может получать данные и отображать их. Делегат в представлении применяется для отображения данных. Когда данные изменяются, делегат напрямую взаимодействует с моделью, уведомляя ее об изменении данных, используя индекс модели.
Модели, представления и делегаты взаимодействуют друг с другом с помощью сигналов и слотов. Сигналы модели информируют представление об изменениях в данных, хранящихся в источнике данных. Сигналы представления предоставляют информацию о взаимодействии пользователя с отображаемыми элементами. Сигналы делегата используются во время редактирования, чтобы сообщить модели и представлению о состоянии редактирования.
Платформа Qt предоставляет набор стандартных классов, которые реализуют архитектуру M/V для управления взаимосвязями между данными и представлением. Причем каждый из компонентов архитектуры определяется абстрактными классами, которые предоставляют общие интерфейсы и, в некоторых случаях, реализации функций по умолчанию. Разделяя функциональные возможности, архитектура обеспечивает гибкость настройки представления данных и позволяет комбинировать широкий спектр источников данных с представлениями.
Базовым классом всех моделей является класс QAbstractItemModel. Этот класс определяет интерфейс, который используется представлениями и делегатами для доступа к данным. Сами данные не обязательно должны храниться в модели. Они может храниться в структуре данных или репозитории, предоставляемом отдельным классом, файле, базе данных или в каком-либо другом компоненте приложения.
Тип QAbstractItemModel предоставляет интерфейс для данных, достаточно гибкий для работы с самыми разными представлениями данных - в виде таблиц, списков и деревьев.
Однако при реализации новых моделей для структур данных в виде списков и таблиц более предпочтительно использовать классы QAbstractListModel и QAbstractTableModel, так как они предоставляют соответствующие реализации по умолчанию. Каждый из этих классов может быть подклассом для создания моделей для специализированных списков и таблиц. Также Qt предоставляет несколько готовых моделей, которые можно использовать для обработки данных:
QStringListModel: используется для хранения простого списка элементов QString
QStandardItemModel управляет более сложными древовидными структурами элементов, каждый из которых может содержать произвольные данные.
QFileSystemModel предоставляет информацию о файлах и каталогах в локальной файловой системе.
QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel используются для доступа к базам данных
Представления (Views) представляют объекты классов, унаследованных от абстрактного класса QAbstractItemView. Для различных типов представлений предусмотрен ряд реализаций:
QListView отображает список элементов
QTableView отображает данные из модели в виде таблицы
QTreeView показывает данные модели в виде дерева
Хотя эти классы представляют собой готовые к использованию реализации, также можно создать их подклассы для большей настройки представлений. В частности, в фреймворке Qt уже имеется ряд виджетов, которые унаследованы от этих классов
Делегаты обеспечивают контроль над представлением элементов, отображаемых в представлении. Шаблон M/V, в отличие от шаблона MVC, не имеет специального компонента для обработки ввода пользователя. Представление в первую очередь отвечает за отображение данных модели пользователю и позволяет ему взаимодействовать с ней. Чтобы добавить некоторую гибкость в способ получения действий пользователя, ввод пользователя обрабатываются делегатами.
Делегаты представляют объекты абстрактного класса QAbstractItemDelegate. Qt также предоставляет две реализацию по умолчанию для различных ситуаций - класс QStyledItemDelegate и QItemDelegate. Разница между ними в том, что QStyledItemDelegate использует текущий стиль для рисования своих элементов. Поэтому рекомендуеncz использовать QStyledItemDelegate в качестве базового класса при реализации пользовательских делегатов или при работе с таблицами стилей Qt.
Рассмотрим простейший пример связи модели и представления:
#include <QApplication> #include <QWidget> #include <QListView> #include <QStringListModel> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget* widget = new QWidget; widget->setWindowTitle("METANIT.COM"); widget->setMinimumHeight(150); widget->setMinimumWidth(250); // определяем данные для модели QStringList list = { "Tom", "Bob", "Sam" }; // определяем модель QStringListModel *model = new QStringListModel(list); // определяем представление QListView *view = new QListView(widget); // устанавливаем модель для представления view->setModel(model); widget->show(); return a.exec(); }
Здесь модель представляет объект QStringListModel
, который инкапсулирует список строк. Собственно список строк - QStringList - это и есть те данные, с которыми работает модель.
В качестве представления здесь применяется объект QListView - виджет, который отображает элементы модели в сиде списка. Для установки модели у представления применяется метод setModel(), в который передается объект модели:
view->setModel(model);
Таким образом, QListView будет связан с моделью QStringListModel и автоматически отобразит ее данные.