Qt:Документация 4.3.2/model-view-delegate

Материал из Wiki.crossplatform.ru

Перейти к: навигация, поиск
40px Внимание: Актуальная версия перевода документации находится здесь

__NOTOC__

Image:qt-logo.png

Главная · Все классы · Основные классы · Классы по группам · Модули · Функции

Image:trolltech-logo.png

[Предыдущая: Обработка выбора элементов в представлениях ] [ Содержание ] [Следующая: Удобные классы представлений элементов ]

Содержание

[править] Классы делегатов

[править] Концепции

В отличие от MVC, архитектура модель\представление не включает полностью независимые компоненты для управления взаимодействием с пользователем. Как правило, представление отвечает за представление пользователю данных модели и за обработку пользовательского ввода. Чтобы придать немного гибкости способу, которым этот ввод получается, взаимодействие осуществляется с помощью делегатов (delegates). Эти компоненты предоставляют возможности ввода, а также отвечают за отрисовку индивидуальных элементов в некоторых представлениях. Стандартный интерфейс управления делегатами определен в классе QAbstractItemDelegate.

Ожидается, что делегаты способны самостоятельно отрисовывать свое содержимое реализуя функции paint() и sizeHint(). Однако, простые основанные на виджетах делегаты могут создавать подкласс QItemDelegate вместо QAbstractItemDelegate, и получить преимущества реализации по умолчанию этих функций.

Редакторы для делегатов могут быть реализованы либо с использованием виджетов для управления процессом редактирования либо непосредственной обработкой событий. Первый подход раскрывается в этой главе, а также показан в примере Spin Box Delegate.

Пример Pixelator показывает как создавать пользовательский делегат, выполняющего специализированный рендеринг для представления таблицы.

[править] Использование существующих делегатов

Стандартные представления, поставляемые вместе с, используют экземпляры класса QItemDelegate для предоставления средств редактирования. Эта реализация по умолчанию интерфейса делегата отображает элементы в обычном стиле для каждого из стандартных представлений: QListView, QTableView и QTreeView.

Стандартные представления используют делегат по умолчанию, обрабатывающий все стандартные роли. Способ их интерпретации описывается в документе QItemDelegate.

Функция itemDelegate() возвращает делегат, используемый представлением. Функция setItemDelegate() позволяет вам установить пользовательский делегат для стандартного представления и важно использовать эту функцию когда устанавливается делегат для пользовательского представления.

[править] Простой делегат

Реализованный здесь делегат использует QSpinBox для предоставления средств редактирования и предназначен в основном для использования с моделями для отображения целых чисел. Хотя мы установили пользовательскую основанную на целых числах модель таблицы для этой цели, мы легко можем использовать вместо нее QStandardItemModel, так как управлять вводом данных будет пользовательский делегат. Мы создадим представление таблицы для отображения содержимого модели и оно будет использовать пользовательский делегат для редактирования.

Файл:Spinboxdelegate-example.png

Мы создаем подкласс делегата от QItemDelegate поскольку мы хотим писать функции пользовательского вывода на экран. Однако, мы все же должны предоставить функции для управления виджетом редактора:

 class SpinBoxDelegate : public QItemDelegate
 {
     Q_OBJECT
 
 public:
     SpinBoxDelegate(QObject *parent = 0);
 
     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                           const QModelIndex &index) const;
 
     void setEditorData(QWidget *editor, const QModelIndex &index) const;
     void setModelData(QWidget *editor, QAbstractItemModel *model,
                       const QModelIndex &index) const;
 
     void updateEditorGeometry(QWidget *editor,
         const QStyleOptionViewItem &option, const QModelIndex &index) const;
 };

Обратите внимание, что при создании делегата виджеты-редакторы не устанавливаются. Мы только создаем виджет-редактор когда это необходимо.

[править] Предоставление редактора

В этом примере, когда представление таблицы нуждается в редакторе, оно просит делегат предоставить виджет-редактор, соответствующий модифицируемому элементу. Функция createEditor() снабжает всем, что необходимо делегату для установки соответствующего виджета:

 QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
     const QStyleOptionViewItem &/* option */,
     const QModelIndex &/* index */) const
 {
     QSpinBox *editor = new QSpinBox(parent);
     editor->setMinimum(0);
     editor->setMaximum(100);
 
     return editor;
 }

Обратите внимание, что мы не нуждаемся в хранении указателя на виджет-редактор, так как представление берет на себя ответственность за его разрушение когда он станет не нужен.

Мы установили фильтр событий по умолчанию делегата на редактор для гарантирования того, что он представит стандартные сокращенные клавиатурные команды редактирования, ожидаемые пользователями. Чтобы сделать возможным более сложное поведение в редактор могут быть добавлены дополнительные сокращенные клавиатурные команды; это обсуждается в разделе Редактирование подсказок.

Представление гарантирует, что данные редакторы и геометрия установлены правильно с помощью вызова функций, которые для этих целей мы определим позднее. Мы можем создать различные редакторы, зависящие от модельного индекса, предоставляемого представлением. Например, если у нас есть столбец целых чисел и столбец строк мы можем вернуть либо QSpinBox либо QLineEdit, в зависимости от того, какой столбец редактируется.

Делегат должен предоставить функцию копирования данных модели в редактор. В этом примере мы читаем данные, хранящиеся в роли вывода на экран (display role), и соответственно устанавливаем значение в окошке счетчика.

 void SpinBoxDelegate::setEditorData(QWidget *editor,
                                     const QModelIndex &index) const
 {
     int value = index.model()->data(index, Qt::DisplayRole).toInt();
 
     QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
     spinBox->setValue(value);
 }

В этом примере мы знаем, что виджет-редактор это окошко счетчика, но мы можем предоставлять различные редакторы для разных типов данных в модели, в этом случае мы должны привести виджет к соответствующему типу до подключения его функций-членов.

[править] Запись данных в модель

Когда пользователь завершает редактирования значения в окошке счетчика, представление просит делегата сохранить отредактированное значение в модели, вызвав функцию setModelData().

 void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
                                    const QModelIndex &amp;index) const
 {
     QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
     spinBox->interpretText();
     int value = spinBox->value();
 
     model->setData(index, value, Qt::EditRole);
 }

Так как представление управляет виджетами-редакторами делегата, мы должно только обновить модель с предоставленным редактором содержимым. В этом случае мы удостоверяемся в том, что окошко счетчика обновилось и обновляем модель содержащую значение, используя заданный индекс.

Стандартный класс QItemDelegate сообщает представлению когда он завершил редактирование испуская сигнал closeEditor(). Представление проверяет, что виджет-редактор закрыт и уничтожен. В этом примере мы предоставили только простые средства редактирования, поэтому нам никогда не понадобится испускать этот сигнал.

Все операции над данными выполняются через интерфейс, предоставляемый QAbstractItemModel. Это делает делагата по большей части независимым от типа данных, с которыми он манипулирует, но должны быть сделаны некоторые допущения в порядке использования определенных типов виджетов-редакторов. В этом примере мы предполагали, что модель всегда содержит целые числа, но мы можем использовать этот делегат с другими видами моделей, поскольку QVariant предоставляет удобные значения по умолчанию для непредвиденных данных.

[править] Обновление геометрии редактора

За управление геометрией редактора отвечает делегат. Геометрия должна быть установлена при создании редактора и при измении размеров или положения элемента. К счастью, представление предоставляет всю необходимую информацию о геометрии внутри объекта опция представления (view option).

 void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
     const QStyleOptionViewItem &amp;option, const QModelIndex &amp;/* index */) const
 {
     editor->setGeometry(option.rect);
 }

В этом случае мы используем только информацию, предоставляемую опцией представления в прямоугольнике элемента. Делегат, который отображает элементы с несколькими примитивами, не использует прямоугольник элемента непосредственно. Он поместит редактор в зависимости от других примитивов в элементе.

[править] Редактирование подсказок

После редактирования делегаты должны предоставить другим компонентам подсказки о результате процесса редактирования и предоставить подсказки, которые будут помогать любым последующим операциям редактирования. Это достигается испусканием сигнала closeEditor() с соответствующей подсказкой. Эту обязанность берет на себя по умолчанию фильтр событий QItemDelegate, который мы установили на окошко счетчика при его созании.

Поведение окошка счетчика можно настраивать, чтобы сделать его более дружественным. В фильтре событий по умолчанию, предоставляемом QItemDelegate, если пользователь нажмет Return для подтверждения своего выбора в окошке счетчика, делегат фиксирует значение в модели и закрывает окошко счетчика. Мы можем изменить это поведение, установив на окошко счетчика свой собственный фильтр событий и предоставив подсказки редактирования, соответствующие нашим нуждам; например, мы можем испустить closeEditor() с подсказкой EditNextItem для автоматического начала редактирвоания следующего элемента в представлении.

Другим подходом, не требующим использования фильтра событий, является предоставление нашего собственного виджета-редактора, возможно унаследованный для удобства от QSpinBox. Альтернативным подходом будет передать нам больше контроля над поведением виджета-редактора за счет написания дополнительного кода. В большинстве случаев более удобно установить фильтр событий в делегате, если вам необходимо настраивать поведение стандартного виджета-редактора Qt.

Делегаты не испускают эти подсказки, но тогда они будут слабее интегрированы в приложения и будут менее удобны, чем те, что испускают подсказки для поддержки общепринятых действий редактирования.

[Предыдущая: Обработка выбора элементов в представлениях ] [ Содержание ] [Следующая: Удобные классы представлений элементов ]



Copyright © 2007 Trolltech Trademarks
Qt 4.3.2