Программирование модели/представления
Введение в программирование модели/представления
Qt содержит набор классов представлений элементов, которые используют архитектуру модели/представления для управления взаимосвязью данных и способом их отображения пользователю. Разделение функций, введенное этой архитектурой, предоставляет разработчикам большую гибкость в настройке отображения элементов и предоставляет стандартный интерфейс модели для использования широкого спектра источников данных с существующими представлениями элементов. В этом документе мы даем краткое введение в парадигму модели/представления, описываем вовлеченные понятия и архитектуру системы представлений элементов. Каждый из компонентов архитектуры объяснен, и приведены примеры, демонстрирующие, как использовать предоставленные классы.
Архитектура модели/представления
Модель-Представление-Контроллер (MVC) — это шаблон проектирования, возникший в Smalltalk, который часто используется при создании пользовательских интерфейсов. В Шаблонах проектирования, Гамма и др. пишут:
MVC состоит из трех видов объектов. Модель — это объект приложения, Представление — его экранное отображение, а Контроллер определяет способ реакции пользовательского интерфейса на ввод пользователя. До MVC, конструкции пользовательских интерфейсов имели тенденцию объединять эти объекты. MVC их разъединяет для повышения гибкости и повторного использования.
Если объекты представления и контроллера объединены, результатом является архитектура модели/представления. Это по-прежнему отделяет способ хранения данных от способа их отображения пользователю, но предоставляет более простую структуру на основе тех же принципов. Это разделение позволяет отображать одни и те же данные в нескольких различных представлениях и реализовывать новые типы представлений без изменения базовых структур данных. Для гибкой обработки ввода пользователя мы вводим понятие делегата. Преимущество наличия делегата в этой структуре заключается в том, что это позволяет настраивать способ отображения и редактирования элементов данных.
|
Архитектура модель/представление Модель взаимодействует с источником данных, предоставляя интерфейс для других компонентов архитектуры. Характер взаимодействия зависит от типа источника данных и способа реализации модели. Представление получает индексы модели от модели; это ссылки на элементы данных. Предоставляя индексы модели модели, представление может извлекать элементы данных из источника данных. В стандартных представлениях делегат отображает элементы данных. При редактировании элемента делегат взаимодействует напрямую с моделью, используя индексы модели. |
В общем случае классы модели/представления можно разделить на три группы, описанные выше: модели, представления и делегаты. Каждый из этих компонентов определяется абстрактными классами, которые предоставляют общие интерфейсы и, в некоторых случаях, стандартные реализации функций. Абстрактные классы предназначены для создания подклассов, чтобы обеспечить полный набор функциональности, ожидаемый другими компонентами; это также позволяет создавать специализированные компоненты.
Модели, представления и делегаты взаимодействуют друг с другом с помощью сигналов и слотов:
- Сигналы от модели информируют представление об изменениях данных, хранящихся в источнике данных.
- Сигналы от представления предоставляют информацию о взаимодействии пользователя с отображаемыми элементами.
- Сигналы от делегата используются во время редактирования, чтобы сообщать модели и представлению о состоянии редактора.
Модели
Все модели элементов основаны на классе QAbstractItemModel. Этот класс определяет интерфейс, используемый представлениями и делегатами для доступа к данным. Сами данные не обязательно должны храниться в модели; они могут храниться в структуре данных или репозитории, предоставляемом отдельным классом, файлом, базой данных или каким-либо другим компонентом приложения.
Основные концепции, связанные с моделями, представлены в разделе о Моделях.
QAbstractItemModel предоставляет интерфейс к данным, достаточно гибкий для обработки представлений, которые представляют данные в виде таблиц, списков и деревьев. Однако при реализации новых моделей для структур данных типа список и таблица классы QAbstractListModel и QAbstractTableModel являются лучшими стартовыми точками, так как они предоставляют соответствующие реализации по умолчанию для общих функций. Каждый из этих классов может быть расширен, чтобы предоставить модели, которые поддерживают специализированные виды списков и таблиц.
Процесс расширения моделей обсуждается в разделе Создание новых моделей.
Qt предоставляет некоторые готовые модели, которые можно использовать для обработки элементов данных:
- QStringListModel используется для хранения простого списка элементов QString.
- QStandardItemModel управляет более сложными древовидными структурами элементов, каждый из которых может содержать произвольные данные.
- QFileSystemModel предоставляет информацию о файлах и каталогах в локальной файловой системе.
- QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel используются для доступа к базам данных с использованием соглашений модели/представления.
Если эти стандартные модели не удовлетворяют вашим требованиям, вы можете расширить QAbstractItemModel, QAbstractListModel или QAbstractTableModel, чтобы создать свои собственные пользовательские модели.
Представления
Для разных типов представлений предоставляются полные реализации: QListView отображает список элементов, QTableView отображает данные из модели в таблице, а QTreeView отображает элементы модели данных в иерархическом списке. Каждый из этих классов основан на абстрактном базовом классе QAbstractItemView. Хотя эти классы являются готовыми реализациями, они также могут быть расширены для предоставления настраиваемых представлений.
Доступные представления рассматриваются в разделе Классы представлений.
Делегаты
QAbstractItemDelegate — абстрактный базовый класс для делегатов в рамках модели/представления. Реализация делегата по умолчанию предоставляется классом QStyledItemDelegate, и этот делегат используется как делегат по умолчанию стандартными представлениями Qt. Однако QStyledItemDelegate и QItemDelegate являются независимыми альтернативами для рисования и предоставления редакторов для элементов в представлениях. Разница между ними заключается в том, что QStyledItemDelegate использует текущий стиль для рисования своих элементов. Поэтому мы рекомендуем использовать QStyledItemDelegate в качестве базового класса при реализации пользовательских делегатов или при работе со стилями Qt.
Делегаты описаны в разделе Классы делегатов.
Сортировка
Существует два способа подхода к сортировке в архитектуре модели/представления; выбор подхода зависит от вашей модели.
Если ваша модель сортируема, то есть если она переопределяет функцию QAbstractItemModel::sort(), как QTableView, так и QTreeView предоставляют API, который позволяет вам программно сортировать данные модели. Кроме того, вы можете включить интерактивную сортировку (то есть, позволяя пользователям сортировать данные, щелкнув заголовки представления), подключив сигнал QHeaderView::sortIndicatorChanged() к слоту QTableView::sortByColumn() или QTreeView::sortByColumn() соответственно.
Альтернативный подход, если ваша модель не имеет требуемого интерфейса или если вы хотите использовать представление списка для представления ваших данных, заключается в использовании модели-прокси для преобразования структуры вашей модели перед представлением данных в представлении. Это подробно описано в разделе Модели-прокси.
Классы-удобства
Несколько удобных классов получены от стандартных классов представлений для выгоды приложений, которые полагаются на базовые представления Qt для элементов и таблицы. Они не предназначены для расширения.
Примеры таких классов включают QListWidget, QTreeWidget и QTableWidget.
Эти классы менее гибкие, чем классы представлений, и не могут быть использованы с произвольными моделями. Мы рекомендуем использовать подход модели/представления для обработки данных в представлениях элементов, если у вас нет острой необходимости в наборе классов на основе элементов.
Если вы хотите воспользоваться преимуществами, предоставляемыми подходом модели/представления, при этом по-прежнему используя интерфейс на основе элементов, рассмотрите использование классов представлений, таких как QListView, QTableView и QTreeView с QStandardItemModel.
Использование моделей и представлений
В следующих разделах объясняется, как использовать шаблон модель/представление в Qt. Каждый раздел включает пример и за ним следует раздел, показывающий, как создавать новые компоненты.
Две модели, включённые в Qt
Две стандартные модели, предоставляемые Qt, — QStandardItemModel и QFileSystemModel. QStandardItemModel — универсальная модель, которую можно использовать для представления различных структур данных, необходимых для представлений списка, таблицы и дерева. Эта модель также хранит элементы данных. QFileSystemModel — модель, которая хранит информацию о содержимом каталога. В результате она не хранит сами элементы данных, а просто представляет файлы и каталоги в локальной файловой системе.
QFileSystemModel предоставляет готовую модель для экспериментов и может быть легко настроена для использования существующих данных. Используя эту модель, мы можем показать, как настроить модель для использования с готовыми представлениями и изучить, как манипулировать данными с помощью индексов модели.
Использование представлений с существующей моделью
Классы QListView и QTreeView являются наиболее подходящими представлениями для использования с QFileSystemModel. Приведенный ниже пример отображает содержимое каталога в представлении дерева рядом с той же информацией в представлении списка. Представления совместно используют выбор пользователя, так что выбранные элементы выделяются в обоих представлениях.
Мы создали QFileSystemModel, чтобы он был готов к использованию, и создали некоторые представления для отображения содержимого каталога. Это демонстрирует самый простой способ использования модели. Создание и использование модели выполняется внутри одной main() функции:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSplitter *splitter = new QSplitter;
QFileSystemModel *model = new QFileSystemModel;
model->setRootPath(QDir::currentPath()); Модель настроена для использования данных с определённой файловой системы. Вызов setRootPath() сообщает модели, какой диск файловой системы отобразить для представлений.
Мы создаём два представления, чтобы мы могли исследовать элементы, хранящиеся в модели, двумя различными способами:
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())); Представления создаются так же, как и другие виджеты. Настройка представления для отображения элементов в модели сводится к вызову его функции setModel() с моделью каталога в качестве аргумента. Мы фильтруем данные, предоставляемые моделью, вызвав функцию setRootIndex() для каждого представления, передав подходящий индекс модели из модели файловой системы для текущего каталога.
Функция index() , используемая в этом случае, уникальна для QFileSystemModel; мы передаём ей каталог, и она возвращает индекс модели. Индексы модели обсуждаются в разделе Классы моделей.
Остальная часть функции просто отображает представления внутри виджета-разделителя и запускает цикл обработки событий приложения:
splitter->setWindowTitle("Two views onto the same file system model");
splitter->show();
return app.exec();
} В приведённом выше примере мы не упомянули, как обрабатывать выбор элементов. Эта тема более подробно рассматривается в разделе о Обработке выборов в представлениях элементов.
Классы моделей
Прежде чем рассматривать, как обрабатываются выборки, вам может быть полезно ознакомиться с концепциями, используемыми в рамках модели/представления.
Основные концепции
В архитектуре модель/представление модель предоставляет стандартный интерфейс, который представления и делегаты используют для доступа к данным. В Qt стандартный интерфейс определён классом QAbstractItemModel. Независимо от того, как элементы данных хранятся в любой базовой структуре данных, все подклассы QAbstractItemModel представляют данные как иерархическую структуру, содержащую таблицы элементов. Представления используют эту конвенцию для доступа к элементам данных в модели, но они не ограничены в том, как они представляют эту информацию пользователю.
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmoAAAFMCAMAAABMEWD7AAAAk1BMVEX////5+flkZGQHBwf6+vr8/Pz7+/v+/v79/f0AAADGxsYUFBQODg42Njbi4uL29vYcHBxwcHDOzs7n5+empqZDQ0MnJyeEhISfn58gICCXl5caGhrz8/OPj4+/v7/X19dSUlJeXl4tLS24uLjc3NyxsbF+fn7s7OzT09NMTEw8PDxqamp3d3eurq7w8PBYWFiJiYmzm4+7AAAgAElEQVR42uxci5aquBIthEAKRfoIKNLi+4Wtrf//dXdXeIg9d9aaWbP6HM4MtAomRaxdtVOVQGjyPPKI5F3t6s1UeNXLvM0x1WVUiXteJd18q+u91xbrc7zme1X5FPXale326gYafeq2W/VtSe9ZUkl7teIvyOo2m9MryVZrzYne0wxfFGvhqyTopbLWoPown20D1pDqJlsiT6nntwpTy021tlUbVYNfPESN+ej5Q18MVjdSg67s1TJKDa3CU7nllTaNJehlMw1r+dPey6brD10fVa/mqCVoTm+EdbPXdfVrk+U33TosJZs2WlVe86UsNrVae0/RVkNPNWvp8kA/UTTFprSleUuTSpG2ZSq5l8a9Nh79gk57rZ+r4bVsp/XrlxqGfhqwkagR1ErUCmqvOa+R0tp7avzVs02J1/qhtvZNK1+89dTMa2lXl1d1DcjGFK+Moj6q9VHtp0W1nmo91bqTQF1HGRkl+zrVqSqIO66LIuU4bh17y7BqhKt4qhzdRO6uJFCjubycOhnoGoLr6CYFluVOBfFLOjUnlHKqslFHE6hBVeJVnv5/CdS4yQCCSdSrwYxBqh9xXf3rEqi8dFP5r41qmv4LUc0j/bTWz06gHl2LJSlP0e5yI6UdCxynz/0JdYom683gRJSu1zMo6VqOkvPckJZJXApDKCvOpLpFNUXn9f1+3+AdkWVZrqZ9MSOD7biOSCuUyRmaxpBaEe3W9x8uoJlyA3FVPIBZ7KHokOwMxI5SDTCOawO3yMjSyimBGF9ZlhJ5Rfl6nZNnfdzXy8rPqMeeZsW+Nshi8+F8I9W2nJLjOZQzfGF+3qKMj+SQSze2eUeUMF/IVaUT8XIgcCXBQIB1h4jbLaq5tONqW5mObJHPCdiiFAUosgydSk4CYk70wfxmkVuVS9dbckGma8EeM4g4naZaYMDaPCBX8BogxlfQX7jmwk08D2lvM2eln5WWKk0XnpQGcehkD8NvppqLfbQcE33G2c3ynCN/WIhihmo5RUOGn1zXz9IxaU3Lxz4F1dzPOL9Zbhep5pF1OkVzTp1IucssW3o04SLKY6ekGp2zfEKqptqANFw1t8ibZNlKHODnvg+quc4tTz9V56mGPBTpBweLKDydw/OBaJJnZyHTMs/gMzJUs+0VxYCbwXW37LBA+WeaLRJQjVZZ7hOo9h5+37TAUM1Ct5eotgSpeGtdoc+dHAdUex8VCAhbRDW9kW4DFFfm4RpUiwKIFaGhmtOtaYG8yZnzDQQRtRGkAWKO4HwC1c7AhQ09TLug2uh9SqfRlN9COko5YlwKpHdQzVoD4nZsqGZ1+bqaNmkpIIt+8GA0BKOw3cgAGk4QSiT5iKd/2HNQbTUXP0f0iR4WBOzTzjbATVT7rmlBO4EeEUsf+w1fwwGvkb8lqm2LEeX2AFTLeHiY8dBasp3nNv+gAU6Q97qLUc1TniVUQyZ93+2GfJow3/0Aam95vxjZ5/2QZYgCqg03fFryB78jZ3Ka2ryKRnyNh4jkOXrcA+/uRzVtGaqFoBonx7092p/t0QL9Kzzwtopqm+GGtsEFVEu48AveYNiw3SGxTvSQ/eiNV+E/SKB/M6pt+WMSpb4ZqyGPgmrBkcfrtyPMHkBF5JnlFXUkUW2IwOvzvItRTU6jkmr71FeHIUcTHo2h7nsYcHTgwvKuMjaVqDbMeQkugWoDMBFRMEt5LcG8Ne70XjI4aPrUc3zrGdUI/jvrtSA4yMwLi7iH4lqP4Lpgj8STsc82mNE8TZ+gwvHI14tOZGQfiT+9qgWYsYlUQ1dGpljguMr2OMSesSOs/d7BqohGmCiw/EG8Va4aNlmJDrs5ljtmUDTqagZnQEhdOd8unCUseAUjGas5vM1mR74zSBB7jk+YBIzLZizAfn56HZUk6NnAk2lmxiA2aDcHzDQBrjj1Y75lnA8RpKCLWzfnqsQIW4fl3IfhmrfG9WaGehitxlCYzPB1BLVpqdRwHlJNVBswOm8HAMcQx6laXw7dDyqZRwcTluhGvLIaVhRrbiltxgTA4lqHAXT4WZpqAY3Pfg4gylAOaFaHse3mH6rqJaKe+4CcHznq9mXFwqOO054deF4z1sXtgDVhidSW6FaYgyy+O6x2nWyXO6g6YOC7Rm9eW6oVka1uboglwvVBryxJkNepRyc4Lur4d4quHc3qk2Fah+AtbSFahxTORAYT+AUyuaxXMBBVDsNUCewc05O44APyLMrrwDVhHun4kK/RVTLEKssBLRUBqgF+sybn2JEoD/gVPSpDR/HzFOMgVKMfWKA3SKgHeFjPhvupfNY/YMZ6F+imtkiGZ+ZSSa6dMb4UEK1N3QTewEf0HgqUfZK4QX7ETDceHSxofe6ywlUJpOY5fPqLJ888oH3DJW3W55G5bSAPyEzAdUcKxGhtYIdBGJCZ9u+DIF59nslUIcKAbhdhFMO5hh4ltfVfiBKS3bKZIJqs70k3zbG8QF4GvB7tPje62pxnskWnmcTstKkSDIifQ1mclVm/0jp/Ihp8jgQRYOkyEjR5/Uy8B/Ipv46uJ/RhR7myk3nqKbjB+aYlBXJ8jbbfz522QXDUOA9UZhfLo+FaeqUZ2GUZ2r8SF1aXJNkZmHu/UjWfg7Mq01QLIkmsI3uNtU0HHWDd/zZCp+Lx+WSh/DZNUhibW6L7GZLOsBt8UN8VhRrH5T075ds94gozC7B7BO71P2usZp8NrdAZeRmrhNo86WskzIjo0yl0ubis1So8h5QI9utsZpXgdDt1Ru1ugaKLm+hU6W2QFRPiMacFUTdgtjVsVrprPqz9lW1rytqX7rlPRWD78UgreWJf3es9hdWdjgW/hxLKwumd5xyMUR1+1/JTU7zdmXxg9SVayFcKXDlADtLdW5lhyl1RDFAgZqW0paoD3UBtcRZnWsBk9zotJxqPYic/wJR7NDplR3V8hNLJmeVN0o/Vj4zPyF4pFKsUrlOVnWIcSqDGP//pJUdTb8oyf+6Xs2Qv4p+9Sm6FWg7u7JDN2W60qKG8of1am2IVR7RNfjfaWXHH4C8rlcrIzk1LnwapF/w3S/47v6C755qPdX6Zwv6Bd/9E1N9VOujWp9Ae6r1CbRPoH0C7aNaH9X6BNpTrU+gfQLtE2j/dHtPtZ5qPdV6qvVU66n2k6jmkXYV/sp/hoAjpdzyDBfHrmpQ/HKqtRX1XhRVtaL/HarpEjQ9j786rZMXO+olCtXd/mYtWnmqWUjTTHl+3QzUe1HuRVGvUbT89yf/+hlo22nenzmt/Jc1HbrYoWl8xjaJSIT2cnxeyDPqoTk8OyUBO2Cxg05PRfXqq6Ir93Wa/+++2EGfBvRenikpHfhiC+fVFx252OFWDwzIcylE5kE1eRZA0cocjiJStN+MSf/qBOqWjwHIfwvx/sfelainqsTgIAyMAm4IVkVxQXHX93+6m4RVa9X29FZatecrHIUaJv9kmWQSEL2c0GVMaAQS9M0MxBMoUD3enl61qUAN8Ba7E6bRWIgNl6wpla0WzEaj0SykMilQG9GLygxBg09HVAWmVm0nHHyorebkhBoFQn0+rWk4vIp6RCA+g63GYzFq864AZmCRaTwWutqlrTW/ylaLoab/AluNoaa8bDUeCw2hppTLViNnjn74otixi58qdmao4FApoHZCqDwhVMSEPg/UimMhLzKtfFCLN8acq7vTdTVRCgXKO5PgxrrasyhQgGQsPlxXM0qnQO9ZwhUlsdXuWMJ9Hlvt1hJuCaEmIbQDxNEVqKE3vXm8B4qkrt5ol/w1qInt6Ck8UIBkLKxATW5L5oEKaFdr16FWjmgBjp264Gn6CkzhLysei9+UGqkz1PRr+WrliBZIENaC7dwr+WpPEi1AOy0biw/y1coXLbhTqqV7cbPS6ka64HBJqqUy4+el2smUNgqLAZel2mnG3p+Satl3ZfTkTLso1XL9VS4FmgYazqCWYVJm+9+/E2rW5xRoRj5H6E+gFrda4APE9Sj+ugLNauLoUDApkoHNwJOWIygX1KBgteVQS0dTZnc8zlYrkA+XHuCkIMKTQO3s6SE3rqEgDP8vDzQaOhyTurLY0R4sC4sdAmqDZrM5GHSofr+mcy8DKh4ChuboXKurb4PioPuDb0sqmy+p+Y/QREbBl9bV+jWQ16GmeX0ufJ8OwspEQs1DgymJiwxp3PrBj+K+EKstRNztQ+NK/tT3hmqjSCh+SRmhlozFFQUqpn3I9Y6A0TumUREYujhq8DpD2AzBSYfqjGnfEphKayF97BacRws0WFiz+Xw0MRvMVylocZVSyBCTEQiU0Z0+zHoad5SIS0fhUS9+0ZeiBblF/4FbcBItkALq1cVoPutQ3WgmkKtUAXUj6bqoVlF1dmuwOSTNPPgmoC4ZUKCpnNGC3Lv5yC04jRZkTDvkTOPSXfS03g6oa85yAf6glg7VCdO+JTCVuJefg9pqTPZPYEbUaqHjoxZudIaohpVFr86Rkr2iVKaRDtFbH0WmXvdn/RAvbYP8MtRyl+pOqCHdIzUi42TdBbF/G3IZznq/Xwc9sg8K3ansNcdrUXHl4U5BWedEb509zPu8jFhiD9QwuCTVp6C2OpwxDQXdca4b+kyd8V1+Q3SsGvJyTow6Ydp3QU37JNRAmkMqCb2YUpllW51GKM0G0+oROmqzgkADRw06aq8FQ3VqWm0Ie7atehvPU2mx+OtQ0z8FNRzdbY8M/7o1gpnV8+Iiy95ARUlWRU2rafDWg0l12oGxalO59DdzPa2Ox1PLBinLDbVsLO6EGoiMaQYzbQ++i089hsCz3JCANx2GprnyayYOVR/VaYFpP7U57zQwRUq9Whl2hxuvBi71DXuzC9ZEQh9FSI9MJZwtli/NHd6GzD24sKt20PmYCBhQUdyfCkzhFHGb/e7xOG3BknopbE2YU83hlQ1ti+SWDq01zHCab806RIMhHKwAqFB8jSq+/qnA1CnTlhCZC3B7Dg7MDiYrVqkNcw5uBXXoBuDNSphWkcQ08U0x0P08uh1uz90CTstb2/a62kKUjaABk9bbFKj4eOhb5MzqcJxCYIWwPkAd+h5U1gAjc8+Xi39wCyhV7QbUcOpmUINGs7e214OBA5UV0tk2wd3isdODziD2CtYLOHrgWB0kFD8bUN8yF2BualByt2AW3HILdPOYQ43yShOmRcy0w8bB6dYAewhTcmbRhrBYVHQHWrQPLW2DTJuZfsK0H4sWaJGeRws0aE3J6umYsPOo4L07XB2Zk0qNq9qjWTAhftZV1bLM6oaeBY42mgjW/h8UKAj1drRg30itLDR6Q9L7INHp6u2QwN3UMQNQoLuGzQo0So/GiTyeIBdMInS0RxlNhh1s16DJkkcLtjejBTwWCWUabOyEaR1m2ro/dNEDkN4cEEs6XtCnObcEmwZDtWOmIdxqyDT5g9GCwrIUyuJpBRoNohqZ1oC6GXgz8GHrwsKOF9R6Q6i4OCfC5TKcOQbqUnBbAEPvnxY7PrmEixNZ3RuK0M2dQMXYgPE2NBs4ylOeyKTolyh6cSJXVlE7XM5Q76MBY9YQbq1kyeTPrKsVmLZwiWlWdNgg00YDFAAOGxMTtHRMRTHnYbs+WgqchSToSUN902LHfTFQkcdAyfYekkm9cmHYbEBjegAPJcGuOgJ7y15ziJPDG6IOpQ5APTw6aJQi3CYrFhb/p1QrTHIFNj3A2TqqOjpqSPRRnJDEVqWnRUgZNYtj4gIY9mgJ7gBdlLwEN9l8+wtSTeY1O1CAq+gH6bBaxUzzxmzW1BGxKB+41Ld3JDuDebm0liEyTSe4HcakAH5Mqkklj4EmlhuS5oJvD8ZNdEB31bWLBjm4CCj0cuYmujPNGbSqro1MHaKnGqAfQ8JO/3+lmqGJbEojhRWi5q0aUBuVtYpw26groqhurbnxH2K/rbqRMbVWg7UfT2IPR1oN05yp3xwDjVtO823EtKDINDuCcOCNrbEGXXSZEGl7HJcNMnFXtV2UJTnTyNN7TGAK/Yh2vPulLcEfbjrkJ9e22wAfPdxQuhg4bfyrmzZondbRAXCWgPegNGw3/k2Bfi4wZcCS/Z2oFqGB21o4RFpnc/TRfpu3OEKyDAE6rT1Ex1YHZ1OAxIb4VrQs+uZ/IzD1jmkSnEVrhn/EX/RpLPyaD9EWp2Ntu2i/Y9r3QG05aN9KjXSOUSE1Mo+hSY5JSb49bhcBxXC8jLs1ZwHcPJnga1BLIi3XUiP77YTQQtiPG1/k/aMNUcxXywgVMp9RaVy0xFBDz/FWamQau4KTHiAZ0/gosvsyDZbyssC0ByV8GykhQnAXeZauQoljO9xynoIeeIpPwr3mY7QJIwXjj62rxeiJgyt63PU+PeqKkV5Ap/Fj0H9zYv9YwvcFpiVPbSgxZnUylHQeImGcM+17oJb1sSj9NpZinuizb2MpqpffsbfgnqqRZdmcd7tq5BNtzpOfC7eXZHOeIn+JVEtcqpdUo56L4rU577U577U576PUyHolvJ4aKSFYhyXYnGcku82uQE1fdfLUyD8t1dKdd1dSI2ksXpvzXpvznm9z3p1Q0892TD0GandEC/R8QS1bTJQFRJQJakLT9TipnnPO8TzeYcOnIv/mB0s1VJJnhGpFQnXjiaBW5M4FpulGqaCWhtsLVZRk3kb5pKBSWbYcZxTJbFH7pPTVE1SNzLYcX2dauapGZpkd0OY6eXVaMtdGXBuOK15G/DZnRj4capTZkRLqEKFKXG3wQGhNPsvu9i1tvgkT7shLTKuVrPGPgPokpKQ5l6t/9kHRoM9VLqtL1FUw4tMJLSE8GmqyNadMjTUT+kZ5TMOY0IAInfGp9xxQMwwaCwW6XJp0TGNRZFo8Fj29bGWXecsf1e4NgmAZgVSgYoZ4HlBGLfj8NuVBPL6Un1EgdE+ETgb1M0LDp4BamkYIET90/TLTwtL1mDqPFmhQGRT3QZdmseM8WqDBpJfncTzZYsdZtACZ1oRf0Y2FXNG4yiVTPUBFddJ/InObHx4tOCEUoUa+1lmjjKeJFqRNQ8RlpolyeaAXAlMllWrvA1NPLNXeBaZ+gVS7kNmhENQK2ROl7QeqENTEqx9oPBYItV/XevYFtRfUXlB7Qe0XQ+1lq71stdK5BZR5rmmKwv+05KUo/Cs+8E8JoJYQmtBWIDkhNv2QP+BPkg+V7KL4kNyXXZS/nT5rfEarMMqVgwGPgxqTUSCYDynxORclGKVyCwolZT+WaiVQoEll1J+RaskTw5XD+/jxzynQpCjmVamWhrjLY6sJaLduvxY+yAdDTb+L0O13XLLFS7Y+iO6GDnpyWBQPfl+BB9pqsF/cMRjLpJRKSWw1KkBk3nqpVDvvwQqU9rPfJNSqWjef5T/2rkQxVR2IDkIgURCXivuGVlzR//+6N5OgYqsU216gPnj3llsfasgcZklmzqS4XVGzGwEwx7b7AZi+PBk3p67NczSgnDh6vrwN8U5cZMXx1QhqsiT8sQElIRcDaoGqnH1kQE0YiBB4kgE1YKy7yQbUgJNuxHpI3gkLiBbUyhVqbSHTvh8bUERjNlBLb0CNtFBjORtQ42uoGamgJr6EWpegluSrabDSeY4GlKWDGnHhFsyAts9pa/fX1YwCaTWWtK6mSaixpHU1TUItcV1NQ6hpCrCcW3dPDN7m+Ws1I2ldjWWl1f6fBvRXtVqR19WKZEBLqJVQK6ivlsKAFsNXy9CAJm1MgRvmuTHF0hnQTHy1Emr/FGp4yTD/sKCE2v8CakWIQIsBtTx9tahFxyv7agZC7YkIVJZ5nCuIi+mrncdo/SlfjVsmI6K9y2PxeloNn8/5E1oNZ9kC6rNSZK3GiO6PR1LLX6tdSoHBsh5HoIi1kQHxdpwvHYGqrfnHWk1yp7ouj+mGrLVaVL/9WKtJnTZyL81e817ssKigglG9iWkCPaiciEuv5NvR5DFY9G37oOi0Xhxq3KAKE5wWg1MtKzDtwpt+hRpOyd7Wt7ISMnOoRUKjgZqWFRfaDdQ4LDu2vo8xDue9rsYjel8rIjPm8fbO6s04aL1S3xMz/cv6aha4wbXv7XlmIorL878uUDPhJN5b3jYXqEVD+yy0D1oNHG/6Js5tAX4BaoRwVeGlDtPU0kONw2Iy3sBy428nsByPIOhOwBgrFhr5iZIJGfZ6CODN5ai/CzXjOspozFqhwoLuUIqu3ms5S3hz/EoIhwPApBvA+jQCVUinCuxQr9hzgKqi63kaaqo4Ly431KGIo5RQi4TmNn1/cBGadhGaqYTGYCImAM0hFMOAGjgUZzca+oONmAZ4rwNRwRu6NCCOKKfx+QANZjUO1otHoNRLcLsNDmI3rm1hZbuwRYGd9NFZcSjuPVijtuBtQT1tMtdqSmgws09NMQgvQutF746+H29ILAFnuKUa0/0Uaju7Vf18rFdPQM0ewdjWUNsewZnB0fbhoMt3S3KXySSk+fepn10krm+BrVJ7MNDCQa0lFqjAdwBT0WqLatiwV9CZkT4P5XwsWnTVGgFowrDyLajdnYvW4gmo4SMwRZUKq+FVaMGt0AzY2/gWSZT2G1BrStKRz4deTwu1ygxgdgTEWx8HzvunYbvp0OoCdGSmnt2SvU5nP4KaCV1x/1CoLgDUGBwqSqvVXAhs6o7odaF2mnh7B2wEAYJQ5mjqHeoU8BOoPRJaeqiR0HpDNDRrMeoqoe22H4T221Cr2OvWp6O67KbXapUjwGanem+27Lda2x9s92Q/bw2oj/c1t81vQg01QrV1b6CrokWgBDUNgtoaZ2S7gvlmv1nXFqqTVdyATtHJ4IFofk+rTe9MxvoJrUZCG5BI6nZ7LYXWc1bXBlMXA1oH9KV+C2o/9tVo1HOPPsoDy/Ec2PmNlnxAKv4WD2ctHxDdBbKi5nehxq07XLgFXOxAqA1NcPUxWJo+gEWjPwbP78gIaurICanIEdsVQJ2yiDcQy85XI6EdCEjvKGgSWoWExq9Cm5LmnZCJ3Sv98Cu7BY8i0FS7BZocdUuM3YXew3AFH9OD8DTqYAq9VRePVZ0o3Vqiaw0kZ+X3WmRQN3f2IAItSmbHKKBholZDW7mz1+GuFqJ6Q696JrpgoOjaakJ6smdvU18HHR++tVvwOAJNtVuA9uWIn9CYBUsPpbfD4ORN+EZcaIo+sd9xq5Iqtgjb7fi471EPD3Rb7PBpmfQnUPdOsunopcJPCuCAV4zx9d/qxlLEzA4MsPFOWx1UVO5G2PYCZ6bZwRH0qdVlRCaqJgSFOhe6fD37jSk0jSS06tDWncB6JDTq9trXxdF4fmPqn0BNXcIgmLalsGTvg6gZalQBy1U6dHvajvZMXxVqKrMjuogtp+prQbJgqo+NKoHVV2jLZfStme+BRkIbTZdyW/o6RCk07Sq0cFq/DDDvPVC1UyAZ6MkN47IBG/+4WxBx1JvX2t2fd2MpbmaHnBUmO/NZcjJ4xPV+k4VLVzAWG0mWG1M86lUZdRCMhvhhtyBqN8gLkvB9vice4esq049JROqK14Uag/ddrBWnxc5PXDQrn5OIGOMxRGQKNXUBZ+xGaJ+TiCKh/Z9qC/4A1MraghJqJdRKqL0W1CwYtcvq9hJq2WR21EqolVDLJgItOTtKqBWwjKWEWgm1Hyx2NEuofadiqg6JBKUuSjDDOtCE3YI2JBKUyoFaiQSlLpxEyBMJSikBymW0hk7vvH/KmTVS7Ra4SQSlGiyLWXJcJNKrxI2pYpBeWYWAWgqtVriS480s+Tj6ejEM6NcDTXPJLM0lxxDYbnM+zUMw6TQCsyJPYc6LHXXhHG8HPZ9/uI1N0Xw1BhPf9744/E6QHcN3AtS+HOfw60tq6S5xUI93+nQyY6cQDPVb7hFo54PQfF3/+Iov8xzLHlPlYsdv9i1AjbHtqHKiIvctsBjnTP4nD3b+oV6m47x7XgComTSkaGD8PEg6068qichUI6b/o27q/CuXl4zFCKIrWPRRPDrUyyqJiMmsAXnjn095L3aojIbLDeLZAKcDGrvcinzVyqJvwVNQ4/HeOvca/1gxEoCcoVYUgtJFM2eo3YZl3CSoGR8a/xQMaqUB/YPb7fcMqJOTAf3L7cz+QBZu3osdn9qZ3ddqZTuzV8jsCOtFCwtKrfaqtQV2nqyRRdJq6aGGF0kWK0kUouq/oso9M14cF++hWULtz0DtXOgYK3W8qXk0VbUfLw3oy2R2RBVA/28DykFrpThCKLVanKB0sX+OTF59UfZaDUZppOtCFlqNmrCJr4/DmQSg1Go3ix1xytYErabBcnnhh8hQqzGophAu0S5msK5GqU+r9aRaVX/ix+Ty81BC7S7UJPunZFRmMcpWjX+CGoNNT81g9lDrtSYxeU4ugj3LtzX+EdSeaT0r81GuqvCzr3ZuwlYa0CtnR7C83J6lxES1vFRyfMeAwmgwpxnM3oCaCDVi55Mv3vfVTJgg1MxMuhwT1LSkCNQooXY/AkUBDxaVDSy8hj+B6t6FaaUKYZOYcbhpYHxnUHDHIHAcIj7IC2paUgSqwSJTqBlJ62qshNoDqBlwHHYGS3FcHPX6UixgJfYo3IlkX7nwzEuqDK+XH9TMpHU1I2OtVkLtO/QwCLWZB7Dz0MfwmtDfwXa4hZNsP8UOvbe3t97bSHKxGK8LtefCgrivBo98tTIsiJexLFb0qgmdJoCzghHsHZj7YW1QG20ktznbNrx+v+8p8ldGUMspLJC+mpXoq00zi0BLqH0zAkWo7RFqJ4TayoH32qAxarz1e5LE8CYC5a8LtdKAZpHZgXZxg1DbOKDBdgOhP5zBsd+XLIxmp+F5Hmk1mcNY+mol1H6y2IFQI602Eaf6iahkj2KMI+hIdkj01eRBvtpLQy1fAxrt+L3+HiiDVU9RtuoDfHGxXcJ0K7trfTKglcXZSP11A8oMzeBgFcFXk4nvMcLuly9jIRJmlzoFclnMFH1ytK52zVPII1/t96EWkVDGvuSfGFBSqibaBgAh6HIAAB+HSURBVMNgkhjyavxuDCgOZr1T3MMvz4XL6NsUISu11KS/LG6DziciL+VFNqByEEwtPUdjY9HfuAFF2dZ3nZVcwvmHvppigj7z4Fo8ltdw03qWG2y2BeOlMzsm3esO1FkiBcxXe8pXo6QBYuyNJpmrLAJ+46shXGr+3u6A+sB/ptVg1A57IVTHgyVoS0R2vW5Buw43Wg195Z0Qm5eG2p+pLXhGq0HdrS5g9HY6GBDUUdgoYSnlGNQs6lQ2utKBJPhqZ+oULaJHwR+q318aX82Ed28mgp7wG3oVGnto6z5AZ6uazMZ8tfV6t43a6ZUVUxnWFrjalR5G0cW4iKOUvpoJnZk9A0c4qCfeRR1OogdTaiEDN6WZwy24MJyRu/bvwgIa1AkCeyyXko59WAi7DvrppkmjkufJeWmooS6f/okylifCAoSaPYWxHRC+NDGAjZhjbB1eAx3FA67vEWobT0ricZNGUZn/x96V8KfLw+CgHOUSRGUqKg7xAJ36/T/dm7Tg8Z8bzmu+rvy2VUdBpCFp0uR5Tmyb80VtUp/DhzNgeHWDiemtOkk7NlOiJdnW/Sjy60P+ddEEvbao/XZ1+ylR6zjLE4Nby84XtbwG4C5hQDST7gZ6tRDGnCnMS+woiuwe3n4UtRmK2ngvaifnak2TVuU+b+fO1VSY+hqRsKnQctKBOcn7tWXf53RFDZF31wAxw0CtpsoylofO1TqnRzc6d66mQv4GkPRRkFYdWIUje2EHvSGNo15QkuJdAc1pCq2msTuGcHGuFhnQdTxSyylkYz/uup0lfRNYUB5Du7vgwv7yBvQZtdr1BpRELWyiVss6E
Модели также уведомляют любые подключенные представления о изменениях данных через механизм сигналов и слотов.
Этот раздел описывает некоторые основные концепции, которые лежат в основе того, как компоненты получают доступ к данным через класс модели. Более сложные концепции обсуждаются в последующих разделах.
Индексы модели
Для того, чтобы представление данных оставалось отделенным от способа доступа к ним, вводится концепция индекса модели. Каждый элемент информации, который может быть получен через модель, представлен индексом модели. Представления и делегаты используют эти индексы для запроса элементов данных для отображения.
В результате, только модель должна знать, как получить данные, а тип данных, управляемый моделью, может быть определен достаточно обще. Индексы модели содержат указатель на модель, которая их создала, что предотвращает путаницу при работе с несколькими моделями.
QAbstractItemModel *model = index.model();
Индексы модели предоставляют временные ссылки на фрагменты информации и могут использоваться для получения или изменения данных через модель. Поскольку модели могут время от времени перестраивать свою внутреннюю структуру, индексы модели могут стать недействительными и не должны храниться. Если требуется долговременная ссылка на элемент информации, необходимо создать постоянный индекс модели. Это обеспечивает ссылку на информацию, которую модель постоянно обновляет. Временные индексы моделей предоставляются классом QModelIndex, а постоянные индексы моделей — классом QPersistentModelIndex.
Для получения индекса модели, соответствующего элементу данных, модели необходимо указать три свойства: номер строки, номер столбца и индекс модели родительского элемента. В следующих разделах эти свойства подробно описаны и объяснены.
Строки и столбцы
В самом простом виде, к модели можно получить доступ как к простой таблице, в которой элементы расположены по номерам строки и столбца. Это не означает, что базовые данные хранятся в структуре массива; использование номеров строк и столбцов — всего лишь соглашение, позволяющее компонентам взаимодействовать друг с другом. Мы можем получить информацию о любом элементе, указав его номер строки и столбца модели, и получим индекс, представляющий этот элемент:
QModelIndex index = model->index(row, column, ...);
Модели, которые предоставляют интерфейсы к простым структурам данных, таким как списки и таблицы, не нуждаются в дополнительной информации, но, как указано в приведенном коде, нам нужно предоставить больше информации при получении индекса модели.
| <img alt="" src="data:image/png;base64,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 |
|
Строки и столбцы На диаграмме показана модель таблицы, в которой каждый элемент определяется парой номеров строки и столбца. Мы получаем индекс модели, который ссылается на элемент данных, передав соответствующие номера строки и столбца в модель. QModelIndex indexA = model->index(0, 0, QModelIndex()); QModelIndex indexB = model->index(1, 1, QModelIndex()); QModelIndex indexC = model->index(2, 1, QModelIndex()); Элементы верхнего уровня в модели всегда ссылаются, указывая |
Родители элементов
Таблично-подобный интерфейс к данным элементов, предоставляемый моделями, идеально подходит для использования данных в представлении таблицы или списка; система номеров строк и столбцов точно соответствует тому, как представления отображают элементы. Однако структуры, такие как древовидные представления, требуют, чтобы модель предоставляла более гибкий интерфейс к элементам внутри. В результате каждый элемент также может быть родителем другой таблицы элементов, так же, как элемент верхнего уровня в древовидном представлении может содержать другой список элементов.
При запросе индекса элемента модели мы должны предоставить некоторую информацию о родителе элемента. Вне модели единственный способ сослаться на элемент — через индекс модели, поэтому также должен быть указан индекс родительской модели:
QModelIndex index = model->index(row, column, parent);
|
Родители, строки и столбцы На диаграмме показана древовидная модель, в которой каждый элемент определяется родителем, номером строки и номером столбца. Элементы "A" и "C" представлены как элементы-сверстники верхнего уровня в модели: QModelIndex indexA = model->index(0, 0, QModelIndex()); QModelIndex indexC = model->index(2, 1, QModelIndex()); Элемент "A" имеет несколько дочерних элементов. Индекс модели для элемента "B" получается с помощью следующего кода: QModelIndex indexB = model->index(1, 0, indexA); |
Роли элементов
Элементы в модели могут выполнять различные роли для других компонентов, позволяя предоставлять различные типы данных в разных ситуациях. Например, Qt::DisplayRole используется для доступа к строке, которая может отображаться как текст в представлении. Как правило, элементы содержат данные для нескольких различных ролей, а стандартные роли определяются Qt::ItemDataRole.
Мы можем запросить у модели данные элемента, передав ему индекс модели, соответствующий элементу, и указав роль, чтобы получить нужный тип данных:
QVariant value = model->data(index, role);
| <img alt="" src="data:image/png;base64,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 |
|
Роли элементов Роль указывает модели, какой тип данных ссылается. Виджеты могут отображать роли по-разному, поэтому важно предоставить соответствующую информацию для каждой роли. Раздел Создание новых моделей более подробно описывает некоторые конкретные применения ролей. |
Наиболее распространённые способы использования данных элементов покрываются стандартными ролями, определёнными в Qt::ItemDataRole. Предоставляя соответствующие данные элемента для каждой роли, модели могут предоставлять подсказки виджетам и делегатам о том, как элементы должны быть представлены пользователю. Разные виды виджетов могут свободно интерпретировать или игнорировать эту информацию по мере необходимости. Также возможно определить дополнительные роли для целей, специфичных для приложения.
Краткое описание
- Индексы модели предоставляют виджетам и делегатам информацию о местоположении элементов, предоставляемых моделями, способом, независимым от каких-либо базовых структур данных.
- Элементы ссылаются по номерам строк и столбцов, а также по индексу модели родительских элементов.
- Индексы модели создаются моделями по запросу других компонентов, таких как виджеты и делегаты.
- Если для родительского элемента указан действительный индекс модели при запросе индекса с помощью index(), возвращаемый индекс относится к элементу под этим родительским элементом в модели. Полученный индекс относится к дочернему элементу.
- Если для родительского элемента указан недействительный индекс модели при запросе индекса с помощью index(), возвращаемый индекс относится к корневому элементу в модели.
- Роль role отличает различные виды данных, связанных с элементом.
Использование индексов модели
Чтобы продемонстрировать, как данные могут быть извлечены из модели, используя индексы модели, мы настроим QFileSystemModel без виджета и отобразим имена файлов и каталогов в виджете. Хотя это не демонстрирует обычный способ использования модели, это демонстрирует соглашения, используемые моделями при работе с индексами модели.
QFileSystemModel загружается асинхронно, чтобы свести к минимуму использование системных ресурсов. Мы должны учитывать это при работе с этой моделью.
Мы создаём модель файловой системы следующим образом:
QFileSystemModel *model = new QFileSystemModel;
connect(model, &QFileSystemModel::directoryLoaded, [model](const QString &directory) {
QModelIndex parentIndex = model->index(directory);
int numRows = model->rowCount(parentIndex);
});
model->setRootPath(QDir::currentPath); В этом случае мы начинаем с настройки по умолчанию QFileSystemModel. Мы подключаем её к лямбда-функции, в которой мы получим родительский индекс, используя конкретную реализацию index() , предоставленную этой моделью. В лямбда-функции мы считаем количество строк в модели с помощью функции rowCount(). Наконец, мы устанавливаем корневой путь QFileSystemModel, чтобы она начала загрузку данных и сработала лямбда-функция.
Для простоты мы интересуемся только элементами в первом столбце модели. Мы последовательно рассматриваем каждую строку, получая индекс модели для первого элемента в каждой строке и считываем данные, хранящиеся для этого элемента в модели.
for (int row = 0; row < numRows; ++row) {
QModelIndex index = model->index(row, 0, parentIndex); Чтобы получить индекс модели, мы указываем номер строки, номер столбца (ноль для первого столбца) и соответствующий индекс модели для родителя всех элементов, которые мы хотим. Текст, хранящийся в каждом элементе, извлекается с помощью функции data() модели. Мы указываем индекс модели и DisplayRole, чтобы получить данные для элемента в виде строки.
QString text = model->data(index, Qt::DisplayRole).toString();
// Display the text in a widget.
} Приведённый выше пример демонстрирует основные принципы извлечения данных из модели:
- Размеры модели можно найти, используя rowCount() и columnCount(). Эти функции обычно требуют указания родительского индекса модели.
- Индексы модели используются для доступа к элементам в модели. Для указания элемента требуется номер строки, столбца и родительский индекс модели.
- Для доступа к корневым элементам в модели укажите нулевой индекс модели в качестве родительского индекса с %%%CODE_BLOCK_16%%.
- Элементы содержат данные для различных ролей. Чтобы получить данные для конкретной роли, необходимо предоставить индекс модели и роль модели.
Дополнительные материалы
Новые модели могут быть созданы путём реализации стандартного интерфейса, предоставляемого QAbstractItemModel. В разделе Создание новых моделей мы покажем это, создав удобную готовую модель для хранения списков строк.
Классы виджетов
Концепции
В архитектуре модель/виджет виджет получает данные из модели и представляет их пользователю. Способ представления данных не должен соответствовать представлению данных, предоставленному моделью, и может быть полностью отличным от базовой структуры данных, используемой для хранения элементов данных.
Разделение содержимого и представления достигается с помощью стандартного интерфейса модели, предоставляемого QAbstractItemModel, стандартного интерфейса виджета, предоставляемого QAbstractItemView, и использования индексов модели, которые представляют элементы данных общим способом. Виджеты обычно управляют общим представлением данных, полученных из моделей. Они могут самостоятельно отображать отдельные элементы данных или использовать делегаты для обработки функций отображения и редактирования.
Помимо представления данных, виджеты обрабатывают навигацию между элементами и некоторые аспекты выбора элемента. Виджеты также реализуют основные функции пользовательского интерфейса, такие как контекстные меню и перетаскивание. Виджет может предоставлять стандартные средства редактирования для элементов или может работать с делегатом для предоставления пользовательского редактора.
Виджет может быть создан без модели, но модель должна быть предоставлена, прежде чем он сможет отображать полезную информацию. Виджеты отслеживают выбранные пользователем элементы с помощью выделений, которые могут храниться отдельно для каждого виджета или быть общими для нескольких виджетов.
Некоторые виджеты, такие как QTableView и QTreeView, отображают заголовки, а также элементы. Они также реализованы классом виджета QHeaderView. Заголовки обычно используют одну и ту же модель, что и виджет, который их содержит. Они извлекают данные из модели с помощью функции QAbstractItemModel::headerData() и обычно отображают информацию заголовка в виде метки. Новые заголовки могут быть подклассами класса QHeaderView, чтобы предоставить более специализированные метки для виджетов.
Использование существующего виджета
Qt предоставляет три готовых класса виджетов, которые представляют данные из моделей способами, знакомыми большинству пользователей. QListView может отображать элементы из модели в виде простого списка или в виде классического виджета с иконками. QTreeView отображает элементы модели в виде иерархии списков, что позволяет представить глубоко вложенные структуры компактным способом. QTableView представляет элементы из модели в виде таблицы, подобно макету приложения для электронных таблиц.
<img alt="" src="data:image/png;base64,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
Поведение стандартных представлений, показанных выше, должно быть достаточным для большинства приложений. Они предоставляют базовые средства редактирования и могут быть настроены для соответствия потребностям более специализированных пользовательских интерфейсов.
Использование модели
Мы возьмём модель списка строк, которую мы создали в качестве примера модели, настроим её с некоторыми данными и создадим представление для отображения содержимого модели. Всё это можно выполнить в одной функции:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Unindented for quoting purposes:
QStringList numbers;
numbers << "One" << "Two" << "Three" << "Four" << "Five";
QAbstractItemModel *model = new StringListModel(numbers); Обратите внимание, что StringListModel объявлена как QAbstractItemModel. Это позволяет нам использовать абстрактный интерфейс к модели и гарантирует, что код всё ещё работает, даже если мы заменим модель списка строк другой моделью.
Представление списка, предоставляемое QListView, достаточно для представления элементов в модели списка строк. Мы создаём представление и настраиваем модель с помощью следующих строк кода:
QListView *view = new QListView; view->setModel(model);
Представление отображается обычным способом:
view->show();
return app.exec();
} Представление отображает содержимое модели, получая доступ к данным через интерфейс модели. Когда пользователь пытается отредактировать элемент, представление использует делегат по умолчанию для предоставления виджета редактора.
На приведенном изображении показано, как QListView представляет данные в модели списка строк. Поскольку модель редактируема, представление автоматически позволяет редактировать каждый элемент в списке с помощью делегата по умолчанию.
Использование нескольких представлений одной модели
Предоставление нескольких представлений одной и той же модели сводится к установке одной и той же модели для каждого представления. В следующем коде мы создаём два представления таблиц, каждое из которых использует одну и ту же простую модель таблицы, которую мы создали для этого примера:
QTableView *firstTableView = new QTableView;
QTableView *secondTableView = new QTableView;
firstTableView->setModel(model);
secondTableView->setModel(model); Использование сигналов и слотов в архитектуре модель/представление означает, что изменения в модели могут быть переданы во все подключённые представления, обеспечивая, что мы всегда можем получить доступ к тем же данным независимо от используемого представления.
На приведенном изображении показаны два разных вида одной и той же модели, каждый из которых содержит ряд выбранных элементов. Хотя данные модели отображаются последовательно на обоих видах, каждый вид сохраняет собственную внутреннюю модель выбора. Это может быть полезно в определенных ситуациях, но для многих применений желательна общая модель выбора.
Обработка выделения элементов
Механизм обработки выделения элементов в представлениях предоставляется классом QItemSelectionModel. Все стандартные представления по умолчанию строят свои собственные модели выделения и взаимодействуют с ними стандартным образом. Модель выделения, используемая представлением, может быть получена с помощью функции selectionModel(), и модель выделения может быть заменена с помощью setSelectionModel(). Возможность контролировать модель выделения, используемую представлением, полезна, когда требуется предоставить несколько согласованных представлений на одних и тех же данных модели.
Как правило, если вы не наследуете от модели или представления, вам не нужно манипулировать содержимым выделения напрямую. Тем не менее, интерфейс модели выделения может быть доступен при необходимости, и это рассмотрено в Обработка выделений в представлениях элементов.
Совместное использование выделений между представлениями
Хотя удобно, что классы представления по умолчанию предоставляют собственные модели выбора, когда мы используем более одного представления для одной и той же модели, часто желательно, чтобы данные модели и выбор пользователя отображались согласованно во всех представлениях. Поскольку классы представлений позволяют заменить их внутренние модели выбора, мы можем добиться согласованного выбора между представлениями с помощью следующей строки:
secondTableView->setSelectionModel(firstTableView->selectionModel());
Второе представление получает модель выбора для первого представления. Теперь оба представления работают с одной и той же моделью выбора, сохраняя синхронизацию данных и выбранных элементов.
В приведённом выше примере использовались два представления одного типа для отображения данных одной и той же модели. Однако, если использовались два разных типа представлений, выбранные элементы могут быть представлены очень по-разному в каждом представлении; например, непрерывный выбор в представлении таблицы может быть представлен как фрагментированный набор выделенных элементов в представлении дерева.
Классы делегатов
Концепции
В отличие от шаблона Model-View-Controller, в модели/представлении нет полностью отдельного компонента для управления взаимодействием с пользователем. Как правило, представление отвечает за представление данных модели пользователю и обработку пользовательского ввода. Для обеспечения гибкости в способе получения этого ввода взаимодействие осуществляется через делегатов. Эти компоненты обеспечивают возможности ввода и также отвечают за отображение отдельных элементов в некоторых представлениях. Стандартный интерфейс для управления делегатами определён в классе QAbstractItemDelegate.
Ожидается, что делегаты смогут самостоятельно отображать своё содержимое, реализуя функции paint() и sizeHint(). Однако, простые делегаты на основе виджетов могут вместо QAbstractItemDelegate наследовать от QStyledItemDelegate и воспользоваться реализациями этих функций по умолчанию.
Редакторами для делегатов можно реализовать либо с помощью виджетов для управления процессом редактирования, либо обрабатывая события напрямую. Первый подход описан далее в этом разделе, и он также показан в примере Spin Box Delegate.
Пример Pixelator демонстрирует, как создать пользовательского делегата, выполняющего специализированное отображение для представления таблицы.
Использование существующего делегата
Стандартные представления, предоставляемые Qt, используют экземпляры QStyledItemDelegate для обеспечения возможностей редактирования. Эта реализация по умолчанию делегата интерфейса отображает элементы в обычном стиле для каждого из стандартных представлений: QListView, QTableView и QTreeView.
Все стандартные роли обрабатываются делегатом по умолчанию, используемым стандартными представлениями. Способ их интерпретации описан в документации QStyledItemDelegate.
Делегат, используемый представлением, возвращается функцией itemDelegate(). Функция setItemDelegate() позволяет установить пользовательский делегат для стандартного представления, и её необходимо использовать при установке делегата для пользовательского представления.
Простой делегат
Реализованный здесь делегат использует QSpinBox для обеспечения возможностей редактирования и предназначен в основном для использования с моделями, отображающими целые числа. Хотя мы настроили пользовательскую модель таблицы на основе целых чисел для этой цели, мы могли бы легко использовать QStandardItemModel вместо неё, поскольку пользовательский делегат управляет вводом данных. Мы создаём представление таблицы для отображения содержимого модели, и оно будет использовать пользовательский делегат для редактирования.
Мы наследуем делегат от QStyledItemDelegate, потому что не хотим писать пользовательские функции отображения. Однако мы всё ещё должны предоставить функции для управления виджетом редактора:
%%%CODE_BLOCK_23%%Обратите внимание, что виджеты редактора не создаются при создании делегата. Мы создаём виджет редактора только когда он нужен.
Предоставление редактора
В этом примере, когда представлению таблицы требуется редактор, оно запрашивает у делегата виджет редактора, подходящий для редактируемого элемента. Функция createEditor() получает всё необходимое для делегата, чтобы он смог настроить подходящий виджет:
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setFrame(false);
editor->setMinimum(0);
editor->setMaximum(100);
return editor;
}Обратите внимание, что нам не нужно хранить указатель на виджет редактора, так как представление берёт на себя ответственность за его уничтожение, когда он больше не нужен.
Мы устанавливаем стандартный фильтр событий делегата на редактор, чтобы гарантировать, что он предоставляет стандартные сочетания клавиш для редактирования, которые ожидаются пользователями. Дополнительные сочетания клавиш могут быть добавлены в редактор для обеспечения более сложного поведения; они обсуждаются в разделе о Подсказках редактирования.
Представление гарантирует, что данные и геометрия редактора устанавливаются правильно, вызывая функции, которые мы определяем позже для этих целей. Мы можем создавать разные редакторы в зависимости от индекса модели, предоставленного представлением. Например, если у нас есть столбец целых чисел и столбец строк, мы можем вернуть либо QSpinBox, либо QLineEdit, в зависимости от того, какой столбец редактируется.
Делегат должен предоставить функцию для копирования данных модели в редактор. В этом примере мы считываем данные, хранящиеся в роли отображения, и соответствующим образом устанавливаем значение в спин-боксе.
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}В этом примере мы знаем, что виджетом редактора является спин-бокс, но мы могли бы предоставить разные редакторы для разных типов данных в модели, в таком случае нам нужно было бы привести виджет к соответствующему типу перед доступом к его методам-членам.
Отправка данных в модель
Когда пользователь закончил редактирование значения в спин-боксе, представление просит делегат сохранить изменённое значение в модели, вызвав функцию setModelData().
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}Поскольку представление управляет виджетами редактора для делегата, нам нужно только обновить модель с содержимым предоставленного редактора. В данном случае мы гарантируем, что спин-бокс обновлён, и обновляем модель значением, которое он содержит, используя указанный индекс.
Стандартный класс QStyledItemDelegate уведомляет представление, когда оно завершило редактирование, испустив сигнал closeEditor(). Представление гарантирует, что виджет редактора закрыт и уничтожен. В этом примере мы предоставляем только простые возможности редактирования, поэтому нам никогда не нужно излучать этот сигнал.
Все операции с данными выполняются через интерфейс, предоставленный QAbstractItemModel. Это делает делегат в основном независимым от типа данных, которые он обрабатывает, но некоторые предположения должны быть сделаны для использования определённых типов виджетов редактора. В этом примере мы предположили, что модель всегда содержит целые значения, но мы всё ещё можем использовать этот делегат с разными типами моделей, потому что QVariant предоставляет разумные значения по умолчанию для неожиданных данных.
Обновление геометрии редактора
Делегат отвечает за управление геометрией редактора. Геометрия должна быть установлена при создании редактора и при изменении размера или положения элемента в представлении. К счастью, представление предоставляет всю необходимую геометрическую информацию внутри объекта варианта представления.
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option,
const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}В этом случае мы просто используем геометрическую информацию, предоставленную вариантом представления, в прямоугольнике элемента. Делегат, который отображает элементы с несколькими элементами, не будет использовать прямоугольник элемента напрямую. Он расположит редактор относительно других элементов в элементе.
Подсказки редактирования
После редактирования делегаты должны предоставить подсказки другим компонентам о результате процесса редактирования и предоставить подсказки, которые помогут в последующих операциях редактирования. Это достигается путём испускания сигнала closeEditor() с подходящей подсказкой. Это обеспечивается стандартным фильтром событий QStyledItemDelegate, который мы установили на спин-бокс при его создании.
Поведение спин-бокса можно настроить для повышения удобства использования. В стандартном фильтре событий, предоставляемом QStyledItemDelegate, если пользователь нажмёт Enter для подтверждения своего выбора в спин-боксе, делегат применяет значение к модели и закрывает спин-бокс. Мы можем изменить это поведение, установив собственный фильтр событий на спин-бокс и предоставив подсказки редактирования, которые удовлетворяют нашим потребностям; например, мы могли бы испустить closeEditor() с подсказкой EditNextItem, чтобы автоматически начать редактирование следующего элемента в представлении.
Ещё один подход, который не требует использования фильтра событий, заключается в предоставлении собственного виджета редактора, возможно, наследуя QSpinBox для удобства. Этот альтернативный подход даст нам больше контроля над поведением виджета редактора за счёт написания дополнительного кода. Обычно легче установить фильтр событий в делегате, если вам нужно настроить поведение стандартного виджета Qt.
Делегаты не обязаны излучать эти подсказки, но те, которые этого не делают, будут менее интегрированы в приложения и будут менее удобны в использовании, чем те, которые излучают подсказки для поддержки общих действий редактирования.
Обработка выделений в представлениях элементов
Концепции
Модель выделения, используемая в классах представлений элементов, предоставляет общее описание выделений, основанных на возможностях архитектуры модели/представления. Хотя стандартные классы для управления выделениями подходят для представлений элементов, модель выделения позволяет создавать специализированные модели выделения, которые удовлетворяют требованиям ваших собственных моделей и представлений элементов.
Информация об выделенных элементах в представлении хранится в экземпляре класса QItemSelectionModel. Он сохраняет индексы модели для элементов в одной модели и независим от каких-либо представлений. Поскольку может быть много представлений к одной модели, можно обмениваться выделениями между представлениями, что позволяет приложениям показывать несколько представлений согласованным образом.
Выбор состоит из диапазонов выбора. Они эффективно поддерживают информацию о больших выборках элементов, записывая только начальный и конечный модельные индексы для каждого диапазона выбранных элементов. Несмежные выборки элементов создаются с использованием более одного диапазона выбора для описания выбора.
Выборы применяются к коллекции модельных индексов, хранящихся в модели выбора. Последний применённый выбор элементов известен как текущий выбор. Эффекты этого выбора могут быть изменены даже после его применения с помощью определённых типов команд выбора. Они обсуждаются позже в этом разделе.
Текущий элемент и выбранные элементы
В представлении всегда есть текущий элемент и выбранный элемент — два независимых состояния. Элемент может быть одновременно текущим элементом и выбранным. Представление отвечает за обеспечение всегда текущего элемента, поскольку навигация с помощью клавиатуры, например, требует текущего элемента.
В таблице ниже показаны различия между текущим элементом и выбранными элементами.
| Текущий элемент | Выбранные элементы |
|---|---|
| Может быть только один текущий элемент. | Может быть несколько выбранных элементов. |
| Текущий элемент будет изменён при навигации с помощью клавиш или щелчка мышью. | Состояние выбора элементов устанавливается или сбрасывается в зависимости от нескольких предопределённых режимов — например, одиночный выбор, множественный выбор и т. д. — при взаимодействии пользователя с элементами. |
| Текущий элемент будет отредактирован, если нажата клавиша редактирования F2 или элемент дважды нажат (при условии, что редактирование включено). | Текущий элемент может использоваться вместе с якорем для указания диапазона, который должен быть выбран или убран из выбора (или сочетание того и другого). |
| Текущий элемент обозначается прямоугольником фокуса. | Выбранные элементы обозначаются прямоугольником выбора. |
При манипулировании выборами часто бывает полезно рассматривать QItemSelectionModel как запись состояния выбора всех элементов в модели элементов. После настройки модели выбора можно выбирать, убирать из выбора или переключать состояние выбора коллекций элементов без необходимости знать, какие элементы уже выбраны. Индексы всех выбранных элементов могут быть получены в любое время, а другие компоненты могут быть проинформированы об изменениях в модели выбора с помощью механизма сигналов и слотов.
Использование модели выбора
Стандартные классы представлений предоставляют модели выбора по умолчанию, которые могут быть использованы в большинстве приложений. Модель выбора, принадлежащая одному представлению, может быть получена с помощью функции selectionModel() представления и использована между несколькими представлениями с помощью setSelectionModel(), поэтому построение новых моделей выбора обычно не требуется.
Выбор создаётся путём указания модели и пары модельных индексов для QItemSelection. Это использует индексы для ссылки на элементы в заданной модели и интерпретирует их как верхний левый и нижний правый элементы в блоке выбранных элементов. Для применения выбора к элементам в модели необходимо отправить выбор в модель выбора; это можно сделать несколькими способами, каждый из которых по-разному влияет на уже существующие в модели выбора выборы.
Выбор элементов
Чтобы продемонстрировать некоторые основные особенности выборов, мы создаём экземпляр пользовательской модели таблицы с 32 элементами в общей сложности и открываем представление таблицы для её данных:
TableModel *model = new TableModel(8, 4, &app);
QTableView *table = new QTableView(0);
table->setModel(model);
QItemSelectionModel *selectionModel = table->selectionModel(); Модель выбора по умолчанию представления таблицы извлекается для последующего использования. Мы не изменяем никакие элементы в модели, а вместо этого выбираем несколько элементов, которые представление отобразит в верхнем левом углу таблицы. Для этого нам нужно получить модельные индексы, соответствующие верхнему левому и нижнему правому элементам в области, которую нужно выбрать:
QModelIndex topLeft;
QModelIndex bottomRight;
topLeft = model->index(0, 0, QModelIndex());
bottomRight = model->index(5, 2, QModelIndex()); Чтобы выбрать эти элементы в модели и увидеть соответствующее изменение в представлении таблицы, нам нужно создать объект выбора, а затем применить его к модели выбора:
QItemSelection selection(topLeft, bottomRight);
selectionModel->select(selection, QItemSelectionModel::Select); Выбор применяется к модели выбора с помощью команды, определённой сочетанием флагов выбора. В данном случае используемые флаги приводят к тому, что элементы, записанные в объекте выбора, включаются в модель выбора независимо от их предыдущего состояния. Результирующий выбор отображается представлением.
<img alt="" src="data:image/png;base64,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
Выбор элементов можно изменить с помощью различных операций, определяемых флагами выбора. Результат этих операций может иметь сложную структуру, но он эффективно представлен моделью выбора. Использование различных флагов выбора для управления выбранными элементами описывается при рассмотрении обновления выбора.
Чтение состояния выбора
Индексы модели, хранящиеся в модели выбора, можно прочитать с помощью функции selectedIndexes(). Она возвращает неупорядоченный список индексов модели, по которым можно перебирать, зная, к какой модели они относятся:
const QModelIndexList indexes = selectionModel->selectedIndexes();
for (const QModelIndex &index : indexes) {
QString text = QString("(%1,%2)").arg(index.row()).arg(index.column());
model->setData(index, text);
} В приведенном коде используется цикл for с диапазоном для перебора и модификации элементов, соответствующих индексам, возвращаемым моделью выбора.
Модель выбора генерирует сигналы, чтобы указывать изменения в выборе. Эти сигналы уведомляют другие компоненты об изменениях как всего выбора, так и текущего фокусированного элемента в модели элементов. Мы можем подключить сигнал selectionChanged() к слоту и изучить элементы в модели, которые были выбраны или сняты с выбора при изменении выбора. Слот вызывается с двумя объектами QItemSelection: один содержит список индексов, соответствующих нововыбранным элементам; другой содержит индексы, соответствующие элементам, которые были сняты с выбора.
В следующем коде мы предоставляем слот, который получает сигнал selectionChanged(), заполняет выбранные элементы строкой и очищает содержимое снятых с выбора элементов.
void MainWindow::updateSelection(const QItemSelection &selected,
const QItemSelection &deselected)
{
QModelIndexList items = selected.indexes();
for (const QModelIndex &index : qAsConst(items)) {
QString text = QString("(%1,%2)").arg(index.row()).arg(index.column());
model->setData(index, text);
}
items = deselected.indexes();
for (const QModelIndex &index : qAsConst(items)) {
model->setData(index, QString());
} Мы можем отслеживать текущий фокусированный элемент, подключив сигнал currentChanged() к слоту, который вызывается с двумя индексами модели. Эти индексы соответствуют предыдущему и текущему фокусированному элементу.
В следующем коде мы предоставляем слот, который получает сигнал currentChanged(), и использует полученную информацию для обновления строки состояния QMainWindow:
void MainWindow::changeCurrent(const QModelIndex ¤t,
const QModelIndex &previous)
{
statusBar()->showMessage(
tr("Moved from (%1,%2) to (%3,%4)")
.arg(previous.row()).arg(previous.column())
.arg(current.row()).arg(current.column()));
} Отслеживание выборов, сделанных пользователем, просто с помощью этих сигналов, но мы также можем обновить модель выбора напрямую.
Обновление выбора
Команды выбора предоставляются комбинацией флагов выбора, определенных в QItemSelectionModel::SelectionFlag. Каждый флаг выбора указывает модели выбора, как обновить её внутреннюю запись выбранных элементов, когда вызываются функции select(). Наиболее часто используемый флаг — Select, который инструктирует модель выбора записывать указанные элементы как выбранные. Флаг Toggle заставляет модель выбора инвертировать состояние указанных элементов, выбирая любые снятые с выбора элементы, и снимая с выбора любые текущие выбранные элементы. Флаг Deselect снимает с выбора все указанные элементы.
Индивидуальные элементы в модели выбора обновляются путем создания выбора элементов и их применения к модели выбора. В следующем коде мы применяем второй выбор элементов к модели таблицы, показанной выше, используя команду Toggle для инвертирования состояния выбора заданных элементов.
QItemSelection toggleSelection;
topLeft = model->index(2, 1, QModelIndex());
bottomRight = model->index(7, 3, QModelIndex());
toggleSelection.select(topLeft, bottomRight);
selectionModel->select(toggleSelection, QItemSelectionModel::Toggle); Результаты этой операции отображаются в представлении таблицы, что обеспечивает удобный способ визуализации достигнутого результата:
<img alt="" src="data:image/png;base64,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
По умолчанию команды выбора действуют только на отдельные элементы, указанные индексами модели. Однако флаги, используемые для описания команды выбора, можно комбинировать с дополнительными флагами для изменения целых строк и столбцов. Например, если вы вызываете select() только с одним индексом, но с командой, являющейся комбинацией Select и Rows, вся строка, содержащая элемент, на который ссылаются, выбирается. Следующий код демонстрирует использование флагов Rows и Columns:
QItemSelection columnSelection;
topLeft = model->index(0, 1, QModelIndex());
bottomRight = model->index(0, 2, QModelIndex());
columnSelection.select(topLeft, bottomRight);
selectionModel->select(columnSelection,
QItemSelectionModel::Select | QItemSelectionModel::Columns);
QItemSelection rowSelection;
topLeft = model->index(0, 0, QModelIndex());
bottomRight = model->index(1, 0, QModelIndex());
rowSelection.select(topLeft, bottomRight);
selectionModel->select(rowSelection,
QItemSelectionModel::Select | QItemSelectionModel::Rows); Несмотря на то, что модели выбора предоставлены только четыре индекса, использование флагов выбора Columns и Rows означает, что выбрано два столбца и две строки. На следующем изображении показан результат этих двух выборов:
<img alt="" src="data:image/png;base64,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
Команды, выполняемые над примером модели, все включают накопление выбора элементов в модели. Также можно очистить выбор или заменить текущий выбор новым.
Чтобы заменить текущий выбор новым, объедините другие флаги выбора с флагом Current. Команда с этим флагом указывает модели выбора заменить её текущую коллекцию индексов модели теми, которые указаны в вызове select(). Чтобы очистить все выделения перед добавлением новых, объедините другие флаги выбора с флагом Clear. Это приводит к сбросу коллекции индексов модели выбора.
Выбор всех элементов в модели
Для выбора всех элементов в модели необходимо создать выбор для каждого уровня модели, который охватывает все элементы на этом уровне. Для этого мы получаем индексы, соответствующие элементам в верхнем левом и нижнем правом углах с заданным родительским индексом:
QModelIndex topLeft = model->index(0, 0, parent);
QModelIndex bottomRight = model->index(model->rowCount(parent)-1,
model->columnCount(parent)-1, parent); Выбор строится с этими индексами и моделью. Затем соответствующие элементы выбираются в модели выбора:
QItemSelection selection(topLeft, bottomRight);
selectionModel->select(selection, QItemSelectionModel::Select); Это необходимо выполнить для всех уровней в модели. Для элементов верхнего уровня мы определим родительский индекс обычным способом:
QModelIndex parent = QModelIndex();
Для иерархических моделей используется функция hasChildren() для определения, является ли какой-либо элемент родителем другого уровня элементов.
Создание новых моделей
Разделение функциональности между компонентами модели/представления позволяет создавать модели, которые могут использовать существующие представления. Этот подход позволяет представлять данные из различных источников с помощью стандартных компонентов графического пользовательского интерфейса, таких как QListView, QTableView и QTreeView.
Класс QAbstractItemModel предоставляет интерфейс, достаточно гибкий для поддержки источников данных, организующих информацию в иерархических структурах, что позволяет вставлять, удалять, изменять или сортировать данные каким-либо образом. Он также предоставляет поддержку операций перетаскивания.
Классы QAbstractListModel и QAbstractTableModel обеспечивают поддержку интерфейсов для более простых неиерархических структур данных и проще в использовании в качестве отправной точки для простых моделей списков и таблиц.
В этом разделе мы создадим простую модель только для чтения, чтобы изучить основные принципы архитектуры модель/представление. Позже в этом разделе мы адаптируем эту простую модель так, чтобы пользователи могли изменять элементы.
Пример более сложной модели см. в примере Simple Tree Model.
Требования к подклассам QAbstractItemModel описаны более подробно в документе Model Subclassing Reference.
Проектирование модели
При создании новой модели для существующей структуры данных важно определить, какой тип модели следует использовать для предоставления интерфейса к данным. Если структуру данных можно представить как список или таблицу элементов, можно использовать подклассы QAbstractListModel или QAbstractTableModel, поскольку эти классы предоставляют подходящие реализации по умолчанию для многих функций.
Однако, если основную структуру данных можно представить только в виде иерархической структуры дерева, необходимо использовать подкласс QAbstractItemModel. Такой подход используется в примере Simple Tree Model.
В этом разделе мы реализуем простую модель, основанную на списке строк, поэтому QAbstractListModel предоставляет идеальный базовый класс для построения.
Какой бы ни была форма основной структуры данных, обычно стоит дополнить стандартный API QAbstractItemModel в специализированных моделях тем, который позволяет более естественный доступ к основной структуре данных. Это облегчает заполнение модели данными, сохраняя при этом возможность взаимодействия других общих компонентов модели/представления с ней с помощью стандартного API. Описанная ниже модель предоставляет пользовательский конструктор для этой цели.
Модель-пример только для чтения
Реализованная здесь модель — простая, неиерархическая, модель данных только для чтения, основанная на стандартном классе QStringListModel. Она имеет QStringList в качестве внутреннего источника данных и реализует только необходимое для функционирования модели. Для упрощения реализации мы используем подкласс QAbstractListModel, поскольку он определяет разумное поведение по умолчанию для моделей списков и предоставляет более простой интерфейс, чем класс QAbstractItemModel.
При реализации модели важно помнить, что QAbstractItemModel не хранит никаких данных сам по себе, он просто предоставляет интерфейс, который представления используют для доступа к данным. Для минимальной модели только для чтения достаточно реализовать несколько функций, так как для большинства интерфейсов существуют реализации по умолчанию. Декларация класса следующая:
class StringListModel : public QAbstractListModel
{
Q_OBJECT
public:
StringListModel(const QStringList &strings, QObject *parent = nullptr)
: QAbstractListModel(parent), stringList(strings) {}
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
private:
QStringList stringList;
}; Помимо конструктора модели, нам нужно реализовать только две функции: rowCount() возвращает количество строк в модели и data() возвращает элемент данных, соответствующий заданному индексу модели.
Хорошо оформленные модели также реализуют headerData() для предоставления представлениям дерева и таблиц данных для отображения в их заголовках.
Обратите внимание, что это неиерархическая модель, поэтому нам не нужно беспокоиться о родительско-дочерних отношениях. Если наша модель была иерархической, нам также пришлось бы реализовать функции index() и parent().
Список строк хранится во внутренней переменной stringList.
Размеры модели
Мы хотим, чтобы количество строк в модели совпадало с количеством строк в списке строк. Мы реализуем функцию rowCount() с учетом этого:
int StringListModel::rowCount(const QModelIndex &parent) const
{
return stringList.count();
} Поскольку модель неиерархическая, мы можем без опасений игнорировать индекс модели, соответствующий родительскому элементу. По умолчанию модели, производные от QAbstractListModel, содержат только один столбец, поэтому нам не нужно переопределять функцию columnCount().
Заголовки и данные модели
Для элементов в представлении мы хотим вернуть строки в списке строк. Функция 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)
return stringList.at(index.row());
else
return QVariant();
} Мы возвращаем допустимый QVariant только в том случае, если индекс модели допустим, номер строки находится в диапазоне элементов в списке строк и запрашиваемый роль поддерживается.
Некоторые представления, такие как QTreeView и QTableView, могут отображать заголовки вместе с данными элементов. Если наша модель отображается в представлении с заголовками, мы хотим, чтобы заголовки отображали номера строк и столбцов. Мы можем предоставить информацию о заголовках, переопределив функцию headerData():
QVariant StringListModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
return QStringLiteral("Column %1").arg(section);
else
return QStringLiteral("Row %1").arg(section);
} Опять же, мы возвращаем допустимый QVariant только если роль поддерживается. При определении возвращаемых данных учитывается ориентация заголовка.
Не все представления отображают заголовки с данными элементов, и те, что отображают, могут быть настроены на их скрытие. Тем не менее, рекомендуется реализовать функцию headerData() для предоставления релевантной информации о данных, предоставляемых моделью.
Элемент может иметь несколько ролей, выдавая разные данные в зависимости от указанной роли. Элементы нашей модели имеют только одну роль, DisplayRole, поэтому мы возвращаем данные для элементов независимо от указанной роли. Однако мы можем повторно использовать данные, которые мы предоставляем для DisplayRole, в других ролях, таких как ToolTipRole, которые представления могут использовать для отображения информации об элементах в всплывающей подсказке.
Редактируемая модель
Модель только для чтения показывает, как простые варианты могут быть представлены пользователю, но для многих приложений гораздо полезнее модель списка, которую можно редактировать. Мы можем изменить модель только для чтения, чтобы сделать элементы редактируемыми, изменив функцию data(), которую мы реализовали для только чтения, и реализовав две дополнительные функции: flags() и setData(). В определение класса добавляются следующие объявления функций:
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override; Делаем модель редактируемой
Делегат проверяет, редактируется ли элемент, прежде чем создавать редактор. Модель должна сообщать делегату, что её элементы редактируемы. Мы делаем это, возвращая правильные флаги для каждого элемента в модели; в данном случае мы активируем все элементы и делаем их как выбираемыми, так и редактируемыми:
Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemIsEnabled;
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
} Обратите внимание, что нам не нужно знать, как делегат выполняет фактический процесс редактирования. Нам нужно только предоставить способ для делегата установить данные в модели. Это достигается с помощью функции setData():
bool StringListModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
stringList.replace(index.row(), value.toString());
emit dataChanged(index, index, {role});
return true;
}
return false;
} В этой модели элемент в списке строк, соответствующий индексу модели, заменяется предоставленным значением. Однако прежде чем мы сможем изменить список строк, мы должны убедиться, что индекс допустим, элемент имеет правильный тип и роль поддерживается. По соглашению, мы требуем, чтобы роль была EditRole, поскольку эта роль используется стандартным делегатом элементов. Для логических значений, однако, вы можете использовать Qt::CheckStateRole и установить флаг Qt::ItemIsUserCheckable; для редактирования значения используется флажок.
Внутренние данные в этой модели одинаковы для всех ролей, поэтому эта деталь просто упрощает интеграцию модели со стандартными компонентами.
После установки данных модель должна уведомить представления о том, что некоторые данные изменились. Это делается путём отправки сигнала dataChanged(). Поскольку изменился только один элемент данных, диапазон элементов, указанный в сигнале, ограничен только одним индексом модели.
Также необходимо изменить функцию data() для добавления проверки Qt::EditRole:
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();
} Вставка и удаление строк
Можно изменить количество строк и столбцов в модели. В модели списка строк имеет смысл менять только количество строк, поэтому мы переопределяем только функции для вставки и удаления строк. Они объявлены в определении класса:
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; Так как строки в этой модели соответствуют строкам в списке, функция insertRows() вставляет определённое количество пустых строк в список строк перед указанной позицией. Количество вставленных строк равно заданному количеству строк.
Родительский индекс обычно используется для определения места добавления строк в модели. В этом случае у нас есть только один список строк верхнего уровня, поэтому мы просто вставляем пустые строки в этот список.
bool StringListModel::insertRows(int position, int rows, const QModelIndex &parent)
{
beginInsertRows(QModelIndex(), position, position+rows-1);
for (int row = 0; row < rows; ++row) {
stringList.insert(position, "");
}
endInsertRows();
return true;
} Модель сначала вызывает функцию beginInsertRows() для информирования других компонентов о том, что количество строк собирается измениться. Функция указывает номера строк первой и последней новых строк, которые нужно вставить, и индекс модели для родительского элемента. После изменения списка строк она вызывает endInsertRows() для завершения операции и информирования других компонентов о том, что размеры модели изменились, возвращая true для указания успеха.
Функция удаления строк из модели также проста в написании. Строки, которые нужно удалить из модели, задаются позицией и количеством строк. Мы игнорируем родительский индекс для упрощения реализации и просто удаляем соответствующие элементы из списка строк.
bool StringListModel::removeRows(int position, int rows, const QModelIndex &parent)
{
beginRemoveRows(QModelIndex(), position, position+rows-1);
for (int row = 0; row < rows; ++row) {
stringList.removeAt(position);
}
endRemoveRows();
return true;
} Функция beginRemoveRows() всегда вызывается перед удалением любых базовых данных и указывает первую и последнюю удаляемые строки. Это позволяет другим компонентам получить доступ к данным перед тем, как они станут недоступными. После удаления строк модель вызывает endRemoveRows() для завершения операции и информирования других компонентов о том, что размеры модели изменились.
Следующие шаги
Мы можем отобразить данные, предоставляемые этой моделью или любой другой моделью, используя класс QListView для представления элементов модели в виде вертикального списка. Для модели списка строк этот вид также предоставляет редактор по умолчанию, чтобы элементы можно было изменять. Мы изучаем возможности, предоставляемые стандартными классами представления в Классах представлений.
Документ Справочник по наследованию от модели подробнее рассматривает требования для подклассов QAbstractItemModel и предоставляет руководство по виртуальным функциям, которые необходимо реализовать, чтобы включить различные функции в разных типах моделей.
Классы-помощники для представления элементов
У виджетов, основанных на элементах, есть имена, отражающие их назначение: QListWidget предоставляет список элементов, QTreeWidget отображает многоуровневую древовидную структуру, а QTableWidget предоставляет таблицу элементов ячеек. Каждый класс наследует поведение класса QAbstractItemView, который реализует общее поведение для выбора элементов и управления заголовками.
Список виджетов
Одноуровневые списки элементов обычно отображаются с помощью QListWidget и ряда QListWidgetItem. Виджет списка создаётся так же, как и любой другой виджет:
QListWidget *listWidget = new QListWidget(this);
Элементы списка могут быть добавлены непосредственно в виджет списка при их создании:
new QListWidgetItem(tr("Sycamore"), listWidget);
new QListWidgetItem(tr("Chestnut"), listWidget);
new QListWidgetItem(tr("Mahogany"), listWidget); Они также могут быть созданы без родительского виджета списка и добавлены в список в какой-либо момент позже:
QListWidgetItem *newItem = new QListWidgetItem;
newItem->setText(itemText);
listWidget->insertItem(row, newItem); Каждый элемент в списке может отображать текстовую метку и значок. Можно изменить цвета и шрифт, используемые для отображения текста, чтобы настроить внешний вид элементов. Подсказки, подсказки состояния и подсказки "Что это?" легко настраиваются, чтобы обеспечить надлежащую интеграцию списка в приложение.
newItem->setToolTip(toolTipText);
newItem->setStatusTip(toolTipText);
newItem->setWhatsThis(whatsThisText); По умолчанию элементы в списке представляются в порядке их создания. Списка элементов могут быть отсортированы по критериям, указанным в Qt::SortOrder, чтобы получить отсортированный по алфавиту в прямом или обратном порядке список элементов:
listWidget->sortItems(Qt::AscendingOrder);
listWidget->sortItems(Qt::DescendingOrder); Деревовидные виджеты
Деревья или иерархические списки элементов предоставляются классами QTreeWidget и QTreeWidgetItem. Каждый элемент в древовидном виджете может иметь собственные дочерние элементы и отображать несколько столбцов информации. Древовидные виджеты создаются так же, как и любой другой виджет:
QTreeWidget *treeWidget = new QTreeWidget(this);
Перед добавлением элементов в древовидный виджет необходимо установить количество столбцов. Например, мы можем определить два столбца и создать заголовок, чтобы предоставить метки вверху каждого столбца:
treeWidget->setColumnCount(2);
QStringList headers;
headers << tr("Subject") << tr("Default");
treeWidget->setHeaderLabels(headers); Самый простой способ установить метки для каждого раздела — предоставить список строк. Для более сложных заголовков можно создать элемент дерева, оформить его по своему усмотрению и использовать его в качестве заголовка древовидного виджета.
Элементы верхнего уровня в древовидном виджете создаются с древовидным виджетом в качестве их родительского виджета. Они могут быть вставлены в произвольном порядке, или вы можете обеспечить их упорядочение, указав предыдущий элемент при создании каждого элемента:
QTreeWidgetItem *cities = new QTreeWidgetItem(treeWidget);
cities->setText(0, tr("Cities"));
QTreeWidgetItem *osloItem = new QTreeWidgetItem(cities);
osloItem->setText(0, tr("Oslo"));
osloItem->setText(1, tr("Yes"));
QTreeWidgetItem *planets = new QTreeWidgetItem(treeWidget, cities); Древовидные виджеты обрабатывают элементы верхнего уровня немного иначе, чем другие элементы, расположенные глубже в дереве. Элементы можно удалить из верхнего уровня древовидного виджета, вызвав функцию древовидного виджета takeTopLevelItem(), но элементы из нижних уровней удаляются путем вызова функции родительского элемента takeChild(). Элементы вставляются в верхний уровень дерева с помощью функции insertTopLevelItem(). На нижних уровнях дерева используется функция родительского элемента insertChild().
Легко перемещать элементы между верхним уровнем и нижними уровнями в дереве. Нужно просто проверить, являются ли элементы элементами верхнего уровня или нет, и эта информация предоставляется функцией каждого элемента parent(). Например, мы можем удалить текущий элемент в древовидном виджете независимо от его местоположения:
QTreeWidgetItem *parent = currentItem->parent();
int index;
if (parent) {
index = parent->indexOfChild(treeWidget->currentItem());
delete parent->takeChild(index);
} else {
index = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
delete treeWidget->takeTopLevelItem(index);
} Вставка элемента в другое место в древовидном виджете выполняется по той же схеме:
QTreeWidgetItem *parent = currentItem->parent();
QTreeWidgetItem *newItem;
if (parent)
newItem = new QTreeWidgetItem(parent, treeWidget->currentItem());
else
newItem = new QTreeWidgetItem(treeWidget, treeWidget->currentItem()); Табличные виджеты
Таблицы элементов, похожие на те, что используются в приложениях для работы со электронными таблицами, создаются с помощью QTableWidget и QTableWidgetItem. Они предоставляют прокручиваемую таблицу с заголовками и элементами для использования в ней.
Таблицы могут быть созданы с заданным числом строк и столбцов, или они могут быть добавлены в неразмеренную таблицу по мере необходимости.
QTableWidget *tableWidget;
tableWidget = new QTableWidget(12, 3, this); Элементы создаются вне таблицы перед добавлением в таблицу в нужном месте:
QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg(
pow(row, column+1)));
tableWidget->setItem(row, column, newItem); Горизонтальные и вертикальные заголовки могут быть добавлены в таблицу путём создания элементов вне таблицы и их использования в качестве заголовков:
QTableWidgetItem *valuesHeaderItem = new QTableWidgetItem(tr("Values"));
tableWidget->setHorizontalHeaderItem(0, valuesHeaderItem); Обратите внимание, что строки и столбцы в таблице начинаются с нуля.
Общие функции
Существует ряд функций, относящихся к элементам, общих для каждого из классов-помощников, доступных через одинаковые интерфейсы в каждом классе. Мы представляем их в следующих разделах с примерами для разных виджетов. Обратитесь к списку Классы модели/представления для каждого из виджетов для получения дополнительной информации об использовании каждой используемой функции.
Скрытые элементы
Иногда бывает полезно скрывать элементы в виджете представления элементов, а не удалять их. Элементы для всех вышеперечисленных виджетов можно скрыть и затем снова показать. Вы можете определить, скрыт ли элемент, вызвав функцию isItemHidden(), и элементы можно скрыть с помощью setItemHidden().
Поскольку эта операция основана на элементах, эта же функция доступна для всех трёх классов-помощников.
Выборы
Способ выбора элементов контролируется режимом выбора виджета (QAbstractItemView::SelectionMode). Этот параметр управляет возможностью пользователя выбирать один или несколько элементов и, при выборе нескольких элементов, контролирует, должен ли выбор быть непрерывным диапазоном элементов. Режим выбора работает одинаково для всех вышеперечисленных виджетов.
Выбор одного элемента: Если пользователю нужно выбрать один элемент из виджета, наиболее подходящий SingleSelection режим — по умолчанию. В этом режиме текущий и выбранный элементы совпадают. |
| Многоэлементные выборки: В этом режиме пользователь может переключать состояние выбора любого элемента в виджете, не изменяя существующий выбор, подобно тому, как можно независимо переключать неисключающие флажки. |
Расширенные выделения: Виджеты, которые часто требуют выбора многих смежных элементов, такие как те, что встречаются в электронных таблицах, требуют режима ExtendedSelection. В этом режиме непрерывные диапазоны элементов в виджете можно выделять как мышью, так и с помощью клавиатуры. Сложные выделения, включающие много элементов, не смежных с другими выделенными элементами в виджете, также могут быть созданы при использовании клавиш модификаторов.Если пользователь выбирает элемент без использования клавиши модификатора, существующее выделение очищается. |
Выделенные элементы в виджете считываются с помощью функции selectedItems(), предоставляя список соответствующих элементов, по которым можно итерироваться. Например, мы можем найти сумму всех числовых значений в списке выделенных элементов с помощью следующего кода:
const QList<QTableWidgetItem *> selected = tableWidget->selectedItems();
int number = 0;
double total = 0;
for (QTableWidgetItem *item : selected) {
bool ok;
double value = item->text().toDouble(&ok);
if (ok && !item->text().isEmpty()) {
total += value;
number++;
}
} Обратите внимание, что для режима одиночного выбора текущий элемент будет в выделении. В режимах множественного и расширенного выбора текущий элемент может не находиться в выделении, в зависимости от того, как пользователь сформировал выделение.
Поиск
Часто бывает полезно находить элементы в виджете представления элементов, как для разработчика, так и для предоставления пользователям. Все три удобные классы представления элементов предоставляют общую функцию findItems() для того, чтобы сделать это максимально последовательным и простым.
Элементы ищутся по тексту, содержащемуся в них, в соответствии с критериями, указанными с помощью выбора значений из Qt::MatchFlags. Мы можем получить список соответствующих элементов с помощью функции findItems().
const QList<QTreeWidgetItem *> found = treeWidget->findItems(
itemText, Qt::MatchWildcard);
for (QTreeWidgetItem *item : found) {
item->setSelected(true);
// Show the item->text(0) for each item.
} Вышеприведённый код вызывает выделение элементов в виджете дерева, если они содержат текст, заданный в строке поиска. Эта схема также может использоваться в виджетах списка и таблицы.
Использование перетаскивания с представлением элементов
Инфраструктура перетаскивания Qt полностью поддерживается моделью/представлением. Элементы в списках, таблицах и деревьях могут быть перетащены внутри представлений, а данные могут импортироваться и экспортироваться как данные, закодированные в MIME.
Стандартные представления автоматически поддерживают внутреннее перетаскивание, где элементы перемещаются для изменения порядка их отображения. По умолчанию перетаскивание для этих представлений не включено, поскольку они настроены для самых простых и распространённых случаев использования. Чтобы разрешить перетаскивание элементов, необходимо включить определённые свойства представления, и сами элементы должны также разрешать перетаскивание.
Требования к модели, которая позволяет только экспортировать элементы из представления и не позволяет опускать данные в неё, меньше, чем для модели перетаскивания с полным функционалом.
См. также Справочник по наследованию моделей для получения дополнительной информации о включении поддержки перетаскивания в новые модели.
Использование удобных представлений
Каждый из типов элементов, используемых с QListWidget, QTableWidget и QTreeWidget, настроен по умолчанию на использование другого набора флагов. Например, каждый QListWidgetItem или QTreeWidgetItem изначально включен, допускает выбор, выделение и может использоваться в качестве источника операции перетаскивания; каждый QTableWidgetItem также может быть изменён и использоваться в качестве целевого объекта операции перетаскивания.
Хотя у всех стандартных элементов установлен один или оба флага для перетаскивания, обычно вам нужно установить различные свойства в самом представлении, чтобы воспользоваться встроенной поддержкой перетаскивания:
- Чтобы включить перетаскивание элементов, установите свойство представления dragEnabled в значение
true. - Чтобы позволить пользователю поместить внутренние или внешние элементы в представление, установите свойство viewport() представления viewport() acceptDrops в значение
true. - Чтобы показать пользователю, куда в данный момент будет помещён перетаскиваемый элемент при его опускании, установите свойство представления showDropIndicator. Это предоставляет пользователю постоянно обновляемую информацию о размещении элементов в представлении.
Например, мы можем включить перетаскивание в списке виджета с помощью следующих строк кода:
QListWidget *listWidget = new QListWidget(this); listWidget->setSelectionMode(QAbstractItemView::SingleSelection); listWidget->setDragEnabled(true); listWidget->viewport()->setAcceptDrops(true); listWidget->setDropIndicatorShown(true);
В результате получается список виджет, который позволяет копировать элементы внутри представления, а также позволяет пользователю перетаскивать элементы между представлениями, содержащими данные того же типа. В обоих случаях элементы копируются, а не перемещаются.
Чтобы пользователю позволить перемещать элементы внутри представления, необходимо установить для списка виджета dragDropMode:
listWidget->setDragDropMode(QAbstractItemView::InternalMove);
Использование классов модели/представления
Настройка представления для перетаскивания следует той же схеме, что и при использовании удобных представлений. Например, QListView можно настроить таким же образом, как и QListWidget:
QListView *listView = new QListView(this); listView->setSelectionMode(QAbstractItemView::ExtendedSelection); listView->setDragEnabled(true); listView->setAcceptDrops(true); listView->setDropIndicatorShown(true);
Поскольку доступ к данным, отображаемым представлением, контролируется моделью, используемая модель также должна предоставлять поддержку операций перетаскивания. Действия, поддерживаемые моделью, можно указать, переопределив функцию QAbstractItemModel::supportedDropActions(). Например, операции копирования и перемещения включаются с помощью следующего кода:
Qt::DropActions DragDropListModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
} Несмотря на то, что можно указать любую комбинацию значений из Qt::DropActions, модель должна быть написана так, чтобы поддерживать их. Например, для правильного использования Qt::MoveAction с моделью списка, модель должна предоставить реализацию QAbstractItemModel::removeRows(), либо напрямую, либо, унаследовав реализацию от базового класса.
Включение перетаскивания для элементов
Модели указывают представлениям, какие элементы можно перетаскивать, а какие будут принимать опускания, переопределяя функцию QAbstractItemModel::flags() для предоставления соответствующих флагов.
Например, модель, предоставляющая простой список на основе QAbstractListModel, может включить перетаскивание для каждого элемента, убедившись, что возвращаемые флаги содержат значения Qt::ItemIsDragEnabled и Qt::ItemIsDropEnabled:
Qt::ItemFlags DragDropListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags defaultFlags = QStringListModel::flags(index);
if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
else
return Qt::ItemIsDropEnabled | defaultFlags;
} Обратите внимание, что элементы можно опускать в верхний уровень модели, но перетаскивание включено только для допустимых элементов.
В приведенном выше коде, поскольку модель получена от QStringListModel, мы получаем набор флагов по умолчанию, вызвав её реализацию функции flags().
Кодирование экспортированных данных
При экспорте элементов данных из модели в операции перетаскивания они кодируются в соответствующий формат, соответствующий одному или нескольким типам MIME. Модели объявляют типы MIME, которые они могут использовать для предоставления элементов, переопределяя функцию QAbstractItemModel::mimeTypes(), возвращая список стандартных типов MIME.
Например, модель, которая предоставляет только обычный текст, предоставит следующую реализацию:
QStringList DragDropListModel::mimeTypes() const
{
QStringList types;
types << "application/vnd.text.list";
return types;
} Модель также должна предоставить код для кодирования данных в объявленном формате. Это достигается путем переопределения функции QAbstractItemModel::mimeData() для предоставления объекта QMimeData, как и в любой другой операции перетаскивания.
Следующий код показывает, как каждый элемент данных, соответствующий заданному списку индексов, кодируется как обычный текст и хранится в объекте QMimeData.
QMimeData *DragDropListModel::mimeData(const QModelIndexList &indexes) const
{
QMimeData *mimeData = new QMimeData;
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const QModelIndex &index : indexes) {
if (index.isValid()) {
QString text = data(index, Qt::DisplayRole).toString();
stream << text;
}
}
mimeData->setData("application/vnd.text.list", encodedData);
return mimeData;
} Поскольку функции передаётся список индексов модели, этот подход достаточно универсален для использования как в иерархических, так и в неиерархических моделях.
Обратите внимание, что пользовательские типы данных должны быть объявлены как метаобъекты, и для них должны быть реализованы операторы потока. См. описание класса QMetaObject для получения подробной информации.
Вставка опущенных данных в модель
Способ, которым любая модель обрабатывает опущенные данные, зависит как от её типа (список, таблица или дерево), так и от способа представления её содержимого пользователю. В общем случае подход, используемый для обработки опущенных данных, должен быть наиболее подходящим для базового хранилища данных модели.
Различные типы моделей обрабатывают опущенные данные по-разному. Модели списка и таблицы предоставляют только плоскую структуру, в которой хранятся элементы данных. В результате они могут вставлять новые строки (и столбцы), когда данные опускаются на существующий элемент в представлении, или они могут перезаписывать содержимое элемента в модели с использованием некоторых из предоставленных данных. Модели дерева часто могут добавлять дочерние элементы, содержащие новые данные, в свои базовые хранилища данных, и поэтому будут вести себя более предсказуемо с точки зрения пользователя.
Обработка опущенных данных выполняется переопределением модели QAbstractItemModel::dropMimeData(). Например, модель, которая обрабатывает простой список строк, может предоставить реализацию, которая обрабатывает данные, опущенные на существующие элементы отдельно от данных, опущенных в верхний уровень модели (т. е. на недействительный элемент).
Модели могут запретить опускание на определённые элементы или, в зависимости от опущенных данных, переопределив QAbstractItemModel::canDropMimeData().
Модель сначала должна убедиться, что операция должна быть выполнена, предоставленные данные находятся в формате, который может быть использован, и что их местоположение в модели является допустимым:
bool DragDropListModel::canDropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(action);
Q_UNUSED(row);
Q_UNUSED(parent);
if (!data->hasFormat("application/vnd.text.list"))
return false;
if (column > 0)
return false;
return true;
}
bool DragDropListModel::dropMimeData(const QMimeData *data,
Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
if (!canDropMimeData(data, action, row, column, parent))
return false;
if (action == Qt::IgnoreAction)
return true; Простая модель списка строк одной колонки может указывать на ошибку, если предоставленные данные не являются обычным текстом или если номер столбца, указанный для опускания, недопустим.
Данные, которые должны быть вставлены в модель, обрабатываются по-разному в зависимости от того, опускаются ли они на существующий элемент или нет. В этом простом примере мы хотим разрешить опускания между существующими элементами, перед первым элементом в списке и после последнего.
При опускании индекс модели, соответствующий родительскому элементу, будет либо действительным, указывая на то, что опускание произошло на элемент, либо недействительным, указывая на то, что опускание произошло где-то в представлении, что соответствует верхнему уровню модели.
int beginRow;
if (row != -1)
beginRow = row; Мы сначала проверяем номер строки, чтобы увидеть, можем ли мы использовать его для вставки элементов в модель, независимо от того, действителен ли родительский индекс или нет.
else if (parent.isValid())
beginRow = parent.row(); Если родительский индекс модели действителен, опускание произошло на элемент. В этой простой модели списка мы узнаём номер строки элемента и используем это значение для вставки опущенных элементов в верхний уровень модели.
else
beginRow = rowCount(QModelIndex()); Когда опускание происходит в другом месте представления, и номер строки неприменим, мы добавляем элементы в верхний уровень модели.
В иерархических моделях, когда опускание происходит на элемент, было бы лучше вставить новые элементы в модель в качестве дочерних элементов этого элемента. В приведенном здесь простом примере модель имеет только один уровень, поэтому этот подход не подходит.
Декодирование импортированных данных
Каждая реализация dropMimeData() также должна декодировать данные и вставить их в базовую структуру данных модели.
Для простой модели списка строк закодированные элементы могут быть декодированы и переданы в QStringList:
QByteArray encodedData = data->data("application/vnd.text.list");
QDataStream stream(&encodedData, QIODevice::ReadOnly);
QStringList newItems;
int rows = 0;
while (!stream.atEnd()) {
QString text;
stream >> text;
newItems << text;
++rows;
} Затем строки могут быть вставлены в базовое хранилище данных. Для согласованности это можно сделать через собственный интерфейс модели:
insertRows(beginRow, rows, QModelIndex());
for (const QString &text : qAsConst(newItems)) {
QModelIndex idx = index(beginRow, 0, QModelIndex());
setData(idx, text);
beginRow++;
}
return true;
} Обратите внимание, что модели обычно потребуется предоставить реализации функций QAbstractItemModel::insertRows() и QAbstractItemModel::setData().
Прокси-модели
В рамках модели/представления элементы данных, предоставляемые одной моделью, могут быть использованы любым количеством представлений, и каждое из них может, возможно, представлять одну и ту же информацию совершенно по-разному. Пользовательские представления и делегаты являются эффективными способами предоставления радикально разных представлений одних и тех же данных. Однако приложениям часто требуется предоставить обычные представления на обработанных версиях одних и тех же данных, таких как представления, отсортированные по-разному, по списку элементов.
Хотя кажется уместным выполнять операции сортировки и фильтрации как внутренние функции представлений, такой подход не позволяет нескольким представлениям совместно использовать результаты таких потенциально дорогостоящих операций. Альтернативный подход, связанный с сортировкой внутри самой модели, приводит к похожей проблеме, где каждое представление должно отображать элементы данных, организованные в соответствии с последней операцией обработки.
Для решения этой проблемы модель/представление использует прокси-модели для управления информацией, передаваемой между отдельными моделями и представлениями. Прокси-модели — это компоненты, которые ведут себя как обычные модели с точки зрения представления и получают доступ к данным из исходных моделей от имени этого представления. Сигналы и слоты, используемые моделью/представлением, обеспечивают, что каждое представление обновляется должным образом, независимо от того, сколько прокси-моделей расположено между ним и исходной моделью.
Использование прокси-моделей
Прокси-модели можно вставлять между существующей моделью и любым количеством представлений. Qt поставляется со стандартной прокси-моделью QSortFilterProxyModel, которая обычно создаётся и используется напрямую, но также может быть унаследована для обеспечения пользовательского поведения фильтрации и сортировки. Класс QSortFilterProxyModel можно использовать следующим образом:
QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(parent);
filterModel->setSourceModel(stringListModel);
QListView *filteredView = new QListView;
filteredView->setModel(filterModel); Поскольку прокси-модели наследуются от QAbstractItemModel, они могут подключаться к любому типу представления и могут использоваться совместно между представлениями. Они также могут использоваться для обработки информации, полученной от других прокси-моделей, в схеме конвейера.
Класс QSortFilterProxyModel предназначен для создания и непосредственного использования в приложениях. Более специализированные прокси-модели могут быть созданы путём наследования от этого класса и реализации необходимых операций сравнения.
Настройка прокси-моделей
Как правило, тип обработки, используемой в прокси-модели, включает сопоставление каждого элемента данных из его исходного расположения в исходной модели с другим расположением в прокси-модели. В некоторых моделях у некоторых элементов может отсутствовать соответствующее расположение в прокси-модели; такие модели являются фильтрующими прокси-моделями. Виджеты обращаются к элементам, используя индексы модели, предоставляемые прокси-моделью, и эти индексы не содержат информации об исходной модели или расположении исходных элементов в этой модели.
QSortFilterProxyModel позволяет фильтровать данные из исходной модели перед предоставлением их виджетам, а также позволяет предоставлять виджетам содержимое исходной модели в виде предварительно отсортированных данных.
Настройка моделей фильтрации
Класс QSortFilterProxyModel предоставляет достаточно универсальную модель фильтрации, которую можно использовать в различных распространённых ситуациях. Для продвинутых пользователей QSortFilterProxyModel можно наследоваться, предоставляя механизм, который позволяет реализовывать пользовательские фильтры.
Подклассы QSortFilterProxyModel могут переопределять две виртуальные функции, которые вызываются всякий раз, когда запрашивается или используется индекс модели из прокси-модели:
- filterAcceptsColumn() используется для фильтрации определённых столбцов из части исходной модели.
- filterAcceptsRow() используется для фильтрации определённых строк из части исходной модели.
По умолчанию реализации этих функций в QSortFilterProxyModel возвращают true, чтобы гарантировать, что все элементы передаются виджетам; переопределения этих функций должны возвращать false для фильтрации отдельных строк и столбцов.
Настройка моделей сортировки
Экземпляры QSortFilterProxyModel используют функцию std::stable_sort() для настройки сопоставлений между элементами в исходной модели и элементами в прокси-модели, что позволяет отобразить отсортированную иерархию элементов виджетам без изменения структуры исходной модели. Для обеспечения пользовательского поведения сортировки переопределите функцию lessThan() для выполнения пользовательских сравнений.
Справочник по наследованию от моделей
Подклассы моделей должны предоставить реализации многих виртуальных функций, определённых в базовом классе QAbstractItemModel. Количество этих функций, которые необходимо реализовать, зависит от типа модели — предоставляет ли она виджетам простой список, таблицу или сложную иерархию элементов. Модели, унаследованные от QAbstractListModel и QAbstractTableModel, могут использовать реализации по умолчанию функций, предоставляемых этими классами. Модели, которые отображают элементы данных в древовидных структурах, должны предоставить реализации многих виртуальных функций в QAbstractItemModel.
Функции, которые необходимо реализовать в подклассе модели, можно разделить на три группы:
- Обработка данных элементов: Все модели должны реализовать функции, позволяющие виджетам и делегатам запрашивать размер модели, проверять элементы и извлекать данные.
- Навигация и создание индексов: Иерархические модели должны предоставить функции, которые виджеты могут вызывать для навигации по древовидным структурам, которые они отображают, и получения индексов модели для элементов.
- Поддержка перетаскивания и обработка типов MIME: Модели наследуют функции, которые управляют способом выполнения операций перетаскивания внутри приложения и извне. Эти функции позволяют описывать элементы данных в терминах типов MIME, которые могут понимать другие компоненты и приложения.
Обработка данных элементов
Модели могут предоставлять различные уровни доступа к предоставляемым данным: они могут быть простыми компонентами только для чтения, некоторые модели могут поддерживать операции изменения размеров, а другие могут позволять редактировать элементы.
Доступ только для чтения
Для предоставления доступа только для чтения к данным, предоставляемым моделью, в подклассе модели необходимо реализовать следующие функции:
| flags() | Используется другими компонентами для получения информации о каждом элементе, предоставляемом моделью. Во многих моделях комбинация флагов должна включать Qt::ItemIsEnabled и Qt::ItemIsSelectable. |
| data() | Используется для предоставления данных элемента виджетам и делегатам. Как правило, модели требуется предоставить данные только для Qt::DisplayRole и любых пользовательских ролей, специфичных для приложения, но также рекомендуется предоставлять данные для Qt::ToolTipRole, Qt::AccessibleTextRole и Qt::AccessibleDescriptionRole. См. документацию по перечислению Qt::ItemDataRole для получения информации о типах, связанных с каждой ролью. |
| headerData() | Предоставляет виджетам информацию для отображения в заголовках. Информация извлекается только виджетами, которые могут отображать заголовки. |
| rowCount() | Предоставляет количество строк данных, отображаемых моделью. |
Эти четыре функции должны быть реализованы во всех типах моделей, включая списочные модели (подклассы QAbstractListModel) и табличные модели (QAbstractTableModel подклассы).
Кроме того, следующие функции должны быть реализованы в прямых подклассах QAbstractTableModel и QAbstractItemModel:
| columnCount() | Предоставляет количество столбцов данных, отображаемых моделью. Списочные модели не предоставляют эту функцию, так как она уже реализована в QAbstractListModel. |
Редактируемые элементы
Редактируемые модели позволяют изменять элементы данных и могут также предоставлять функции для вставки и удаления строк и столбцов. Для включения редактирования следующие функции должны быть реализованы корректно:
| flags() | Должен возвращать подходящую комбинацию флагов для каждого элемента. В частности, возвращаемое значение этой функции должно включать Qt::ItemIsEditable в дополнение к значениям, применённым к элементам в модели только для чтения. |
| setData() | Используется для изменения элемента данных, связанного с указанным индексом модели. Чтобы принять пользовательский ввод, предоставляемый элементами пользовательского интерфейса, эта функция должна обрабатывать данные, связанные с Qt::EditRole. Реализация также может принимать данные, связанные со многими различными типами ролей, указанными в Qt::ItemDataRole. После изменения элемента данных модели должны излучать сигнал dataChanged() для информирования других компонентов об изменениях. |
| setHeaderData() | Используется для изменения горизонтальной и вертикальной информации о заголовках. После изменения элемента данных модели должны излучать сигнал headerDataChanged() для информирования других компонентов об изменениях. |
Изменяемые модели
Все типы моделей могут поддерживать вставку и удаление строк. Табличные модели и иерархические модели также могут поддерживать вставку и удаление столбцов. Важно сообщать другим компонентам об изменениях размеров модели как до, так и после их возникновения. В результате для изменения размеров модели можно реализовать следующие функции, но реализации должны гарантировать, что вызываются соответствующие функции для уведомления подключенных виджетов и делегатов:
| insertRows() | Используется для добавления новых строк и элементов данных во все типы моделей. Реализации должны вызывать beginInsertRows() перед вставкой новых строк в любые базовые структуры данных и вызывать endInsertRows() немедленно после. |
| removeRows() | Используется для удаления строк и содержащихся в них элементов данных из всех типов моделей. Реализации должны вызывать beginRemoveRows() перед удалением строк из любых базовых структур данных и вызывать endRemoveRows() немедленно после. |
| insertColumns() | Используется для добавления новых столбцов и элементов данных в табличные и иерархические модели. Реализации должны вызывать beginInsertColumns() перед вставкой новых столбцов в любые базовые структуры данных и вызывать endInsertColumns() немедленно после. |
| removeColumns() | Используется для удаления столбцов и содержащихся в них элементов данных из табличных и иерархических моделей. Реализации должны вызывать beginRemoveColumns() перед удалением столбцов из любых базовых структур данных и вызывать endRemoveColumns() немедленно после. |
Как правило, эти функции должны возвращать true, если операция выполнена успешно. Однако могут быть случаи, когда операция выполнена только частично; например, если вставлено меньше, чем указанное количество строк. В таких случаях модель должна возвращать false, чтобы сообщить любым подключённым компонентам о возможности обработки ситуации.
Сигналы, излучаемые функциями, используемыми в реализациях API изменения размера, предоставляют подключённым компонентам возможность действовать, прежде чем какие-либо данные станут недоступными. Инкапсуляция операций вставки и удаления с помощью функций begin и end также позволяет модели правильно управлять постоянными индексами модели.
Обычно функции begin и end способны информировать другие компоненты об изменениях в базовой структуре модели. Для более сложных изменений структуры модели, возможно, включающих внутреннюю перестройку, сортировку данных или любые другие изменения структуры, необходимо выполнить следующие действия:
- Вызвать сигнал layoutAboutToBeChanged()
- Обновить внутренние данные, представляющие структуру модели.
- Обновить постоянные индексы с помощью changePersistentIndexList()
- Вызвать сигнал layoutChanged()
Эта последовательность может быть использована для любого структурного обновления вместо более высокого уровня и удобных защищенных методов. Например, если модель из двух миллионов строк должна удалить все строки с нечетными номерами, это 1 миллион разрозненных диапазонов по 1 элементу каждый. Было бы возможно использовать beginRemoveRows и endRemoveRows 1 миллион раз, но это, очевидно, было бы неэффективно. Вместо этого это можно сигнализировать как одно изменение макета, которое обновляет все необходимые постоянные индексы сразу.
Ленивая загрузка данных модели
Ленивая загрузка данных модели позволяет эффективно откладывать запросы к информации о модели до тех пор, пока она не потребуется представлениям.
Некоторые модели должны получать данные из удаленных источников или выполнять длительные операции для получения информации о структуре данных. Поскольку представления, как правило, запрашивают как можно больше информации для точного отображения данных модели, полезно ограничить количество возвращаемой им информации, чтобы уменьшить ненужные последующие запросы данных.
В иерархических моделях, где определение количества дочерних элементов заданного элемента является дорогостоящей операцией, полезно обеспечить, чтобы реализация rowCount() модели вызывалась только при необходимости. В таких случаях функция hasChildren() может быть переопределена для обеспечения недорогого способа для представлений проверить наличие дочерних элементов и, в случае QTreeView, нарисовать соответствующее украшение для родительского элемента.
Вне зависимости от того, возвращает ли переопределение hasChildren() true или false, представлению может не потребоваться вызывать rowCount() для определения количества дочерних элементов. Например, QTreeView не нуждается в знании количества дочерних элементов, если родительский элемент не был раскрыт для их отображения.
Если известно, что многие элементы будут иметь дочерние элементы, переопределение hasChildren() для безусловного возвращения true иногда является полезным подходом. Это гарантирует, что каждый элемент впоследствии может быть проверен на наличие дочерних элементов, одновременно ускоряя начальную загрузку данных модели. Единственный недостаток заключается в том, что элементы без дочерних элементов могут быть отображены неправильно в некоторых представлениях, пока пользователь не попытается просмотреть несуществующие дочерние элементы.
Навигация и создание индексов модели
Иерархические модели должны предоставлять функции, которые представления могут вызывать для навигации по структуре дерева, которое они представляют, и получения индексов модели для элементов.
Родители и дети
Поскольку структура, представленная представлениям, определяется базовой структурой данных, каждый подкласс модели должен создать собственные индексы модели, предоставив реализации следующих функций:
| index() | Данная функция позволяет представлениям и делегатам получить доступ к дочерним элементам данного элемента по его индексу модели. Если не найден допустимый дочерний элемент, соответствующий заданной строке, столбцу и индексу родительской модели, функция должна вернуть QModelIndex(), что является недопустимым индексом модели. |
| parent() | Предоставляет индекс модели, соответствующий родителю любого заданного дочернего элемента. Если указанный индекс модели соответствует корневому элементу в модели или если в модели нет допустимого родительского элемента, функция должна вернуть недопустимый индекс модели, созданный с помощью конструктора QModelIndex(). |
Обе вышеуказанные функции используют фабричную функцию createIndex() для генерации индексов для использования другими компонентами. Для моделей обычно требуется предоставить некоторый уникальный идентификатор этой функции, чтобы гарантировать, что индекс модели можно будет повторно связать с соответствующим элементом позже.
Поддержка перетаскивания и обработка типов MIME
Классы модели/представления поддерживают операции перетаскивания, предоставляя поведение по умолчанию, которое достаточно для многих приложений. Однако также возможно настроить способ кодирования элементов во время операций перетаскивания, независимо от того, копируются или перемещаются они по умолчанию, и как они вставляются в существующие модели.
Кроме того, удобные классы представлений реализуют специализированное поведение, которое должно строго соответствовать ожиданиям существующих разработчиков. Раздел «Удобные представления» предоставляет обзор этого поведения.
Данные MIME
По умолчанию встроенные модели и представления используют внутренний тип MIME (application/x-qabstractitemmodeldatalist) для передачи информации об индексах модели. Это указывает данные для списка элементов, содержащих номера строки и столбца каждого элемента и информацию о поддерживаемых ролях каждого элемента.
Данные, закодированные с помощью этого типа MIME, можно получить, вызвав QAbstractItemModel::mimeData() с QModelIndexList, содержащим элементы, которые необходимо сериализовать.
При реализации поддержки перетаскивания в пользовательской модели можно экспортировать элементы данных в специализированных форматах, переопределив следующую функцию:
| mimeData() | Эта функция может быть переопределена для возврата данных в форматах, отличных от внутреннего типа MIME application/x-qabstractitemmodeldatalist по умолчанию.Подклассы могут получить объект QMimeData по умолчанию от базового класса и добавить данные в дополнительные форматы. |
Для многих моделей полезно предоставить содержимое элементов в распространенном формате, представленном типами MIME, такими как text/plain и image/png. Обратите внимание, что изображения, цвета и HTML-документы можно легко добавить в объект QMimeData с помощью функций QMimeData::setImageData(), QMimeData::setColorData() и QMimeData::setHtml().
Прием опущенных данных
Когда операция перетаскивания выполняется над представлением, к базовой модели обращаются для определения типов операций, которые она поддерживает, и типов MIME, которые она может принять. Эта информация предоставляется функциями QAbstractItemModel::supportedDropActions() и QAbstractItemModel::mimeTypes(). Модели, которые не переопределяют реализации, предоставленные QAbstractItemModel, поддерживают операции копирования и внутренний тип MIME по умолчанию для элементов.
При опускании сериализованных данных элемента на представление данные вставляются в текущую модель с помощью её реализации QAbstractItemModel::dropMimeData(). Реализация этой функции по умолчанию никогда не перезапишет данные в модели; вместо этого она пытается вставить элементы данных либо как элементы-сиблинги элемента, либо как дочерние элементы этого элемента.
Для использования реализации по умолчанию QAbstractItemModel для встроенного типа MIME, новые модели должны предоставить переопределения следующих функций:
| insertRows() | Эти функции позволяют модели автоматически вставлять новые данные, используя существующую реализацию QAbstractItemModel::dropMimeData(). |
| insertColumns() | |
| setData() | Позволяет заполнить новые строки и столбцы элементами. |
| setItemData() | Эта функция обеспечивает более эффективную поддержку заполнения новых элементов. |
Для принятия других форм данных эти функции должны быть переопределены:
| supportedDropActions() | Используется для возврата комбинации действий перетаскивания, указывающих типы операций перетаскивания, которые модель принимает. |
| mimeTypes() | Используется для возврата списка типов MIME, которые могут быть декодированы и обработаны моделью. Как правило, типы MIME, которые поддерживаются для ввода в модель, аналогичны тем, которые она может использовать при кодировании данных для использования внешними компонентами. |
| dropMimeData() | Выполняет фактическое декодирование данных, переданных операциями перетаскивания, определяет, куда в модели они будут установлены, и вставляет новые строки и столбцы при необходимости. Как эта функция реализуется в подклассах, зависит от требований данных, представленных каждой моделью. |
Если реализация функции dropMimeData() изменяет размеры модели, вставляя или удаляя строки или столбцы, или если элементы данных изменяются, необходимо позаботиться о том, чтобы были вызваны все соответствующие сигналы. Полезно просто вызвать переопределения других функций в подклассе, таких как setData(), insertRows() и insertColumns(), чтобы гарантировать согласованное поведение модели.
Для обеспечения правильной работы операций перетаскивания важно переопределить следующие функции, которые удаляют данные из модели:
- removeRows()
- removeRow()
- removeColumns()
- removeColumn()
Дополнительную информацию о перетаскивании с помощью представлений элементов см. в разделе Использование перетаскивания с элементами представлений.
Удобные представления
Удобные представления (QListWidget, QTableWidget и QTreeWidget) переопределяют стандартную функциональность перетаскивания для обеспечения менее гибкого, но более естественного поведения, подходящего для многих приложений. Например, поскольку перетаскивание данных в ячейки в QTableWidget более распространено, заменяя существующее содержимое переносимыми данными, базовый модель будет устанавливать данные целевых элементов, а не добавлять новые строки и столбцы в модель. Для получения дополнительной информации о перетаскивании в удобных представлениях можно обратиться к Использование перетаскивания с представлениями элементов.
Оптимизация производительности для больших объёмов данных
Функция canFetchMore() проверяет, есть ли у родителя больше доступных данных, и возвращает true или false соответственно. Функция fetchMore() извлекает данные на основе указанного родителя. Обе эти функции могут быть объединены, например, в запросе к базе данных, включающем инкрементные данные для заполнения QAbstractItemModel. Мы переопределяем canFetchMore() для указания наличия больше данных для извлечения и fetchMore() для заполнения модели по мере необходимости.
Другим примером могут быть динамически заполненные модели дерева, где мы переопределяем fetchMore() при раскрытии ветви в модели дерева.
Если ваше переопределение fetchMore() добавляет строки в модель, вам необходимо вызвать beginInsertRows() и endInsertRows(). Кроме того, как canFetchMore(), так и fetchMore() должны быть переопределены, поскольку их стандартные реализации возвращают false и ничего не делают.
Классы Модель/Представление
Эти классы используют шаблон проектирования модель/представление, в котором базовые данные (в модели) хранятся отдельно от способа их отображения и обработки пользователем (в представлении).
Используется для отображения и редактирования элементов данных из модели |
|
Абстрактный интерфейс для классов модели элементов |
|
Основные возможности для классов представлений элементов |
|
Абстрактная модель, которую можно наследовать для создания одномерных списков моделей |
|
Базовый класс для прокси-моделей элементов, которые могут выполнять сортировку, фильтрацию или другие задачи обработки данных |
|
Абстрактная модель, которую можно наследовать для создания табличных моделей |
|
Реализация модель/представление для представления столбцов |
|
Проксирует несколько исходных моделей, конкатенируя их строки |
|
Сопоставление части модели данных с виджетами |
|
Модель данных для локальной файловой системы |
|
Строка или столбец заголовка для представлений элементов |
|
Проксирует свою исходную модель без изменений |
|
Средства отображения и редактирования элементов данных из модели |
|
Возможность создания создателей редакторов элементов без наследования QItemEditorCreatorBase |
|
Абстрактный базовый класс, который должен быть унаследован при реализации новых создателей редакторов элементов |
|
Виджеты для редактирования данных элементов в представлениях и делегатах |
|
Управляет информацией о выбранных элементах в модели |
|
Отслеживает выбранные элементы представления |
|
Управляет информацией о диапазоне выбранных элементов в модели |
|
Список или представление значков на основе модели |
|
Список виджетов на основе элементов |
|
Элемент для использования с классом представления элементов QListWidget |
|
Используется для поиска данных в модели данных |
|
Содержит роль и данные, связанные с этой ролью |
|
Диапазон над объектами QModelRoleData |
|
Используется для поиска данных в модели данных |
|
Поддержка сортировки и фильтрации данных, передаваемых между другой моделью и представлением |
|
Элемент для использования с классом QStandardItemModel |
|
Возможность регистрировать виджеты без необходимости наследования QItemEditorCreatorBase |
|
Общедоступная модель для хранения пользовательских данных |
|
Модель, которая предоставляет строки представлениям |
|
Средства отображения и редактирования элементов данных из модели |
|
Стандартная модель/представление табличного представления |
|
Представление таблицы на основе элементов с моделью по умолчанию |
|
Элемент для использования с классом QTableWidget |
|
Способ взаимодействия с выбором в модели без использования индексов модели и модели выбора |
|
Стандартная модель/представление древовидного представления |
|
Представление дерева, использующее предварительно определенную модель дерева |
|
Элемент для использования с удобным классом QTreeWidget |
|
Способ перебора элементов в экземпляре QTreeWidget |
Примеры
См. также Пример головоломки с элементами представления.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/model-view-programming.html