На этом шаге мы рассмотрим назначение делегатов и классы, их реализующие.
Все три представления, перечисленные на 145 шаге, дают возможность редактирования текста их элементов. Например, в таблице (класс QTableView) мы можем дважды щелкнуть мышью на любом элементе, после чего в нем появится поле ввода. Введем в это поле новый текст и нажмем клавишу Enter для подтверждения ввода или Esc - для отмены.
За редактирование данных в представлении отвечает особый класс, называемый делегатом. Он создает компонент, в котором будет выполняться редактирование значения (редактор), задает его параметры, заносит в него само редактируемое значение, а по окончании редактирования переносит его назад, в модель.
По умолчанию в качестве делегата используется класс QItemDelegate из модуля QtWidgets. А в качестве компонента-редактора применяется однострочное поле ввода (класс QLineEdit, рассмотренный нами на 103 шаге.
Если мы хотим использовать для редактирования значения в каком-либо столбце или строке другой редактор,- например, многострочное поле ввода, поле ввода даты или целого числа, мы создадим другой делегат и назначим его представлению. Класс, представляющий делегат, должен быть унаследован от класса QStyledItemDelegate.
Иерархия наследования классов QItemDelegate и QStyledItemDelegate:
QObject - QAbstractItemDelegate - QItemDelegate QObject - QAbstractItemDelegate - QStyledItemDelegate
В новом классе-делегате нам следует переопределить следующие методы;
createEditor(self, <Родитель>, <Настройки>, <Индекс>)
Вторым параметром передается ссылка на компонент-представление, который станет родителем создаваемого редактора (список, таблица или иерархический список). Третьим параметром передается экземпляр класса QStyleOptionViewItem, хранящий дополнительные настройки делегата. Четвертым параметром можно получить индекс текущего элемента модели, представленный экземпляром класса QModelIndex.
Метод createEditor() должен создать компонент-редактор, задать для него в качестве родителя компонент-представление (он передается вторым параметром) и вернуть созданный компонент в качестве результата.
Чтобы отказаться от использования собственного делегата и указать представлению использовать делегат по умолчанию, в методе createEditor() следует вернуть значение None;
setEditorData(self, <Редактор>, <Индекс>)
Вторым параметром передается компонент-редактор, а третьим - индекс текущего элемента модели в виде экземпляра класса QModelIndex;
updateEditorGeometry(self, <Редактор>, <Настройки>, <Индекс>)
Вторым параметром передается ссылка на компонент-редактор, третьим - ссылка на экземпляр класса QStyleOptionViewItem, хранящий настройки делегата, четвертым - индекс текущего элемента модели, представленный экземпляром класса QModelIndex.
Размеры отведенной под редактор области мы можем получить из атрибута rect экземпляра класса QStyleOptionViewItem, переданного третьим параметром (полное описание класса QStyleOptionViewItem приведено на странице https://doc.qt.io/qt-5/qstyleoptionviewitem.html, а описание класса QStyleOption, от которого он порожден, - на странице https://doc.qt.io/qt-5/qstyleoption.html);
setModelData(self, <Редактор>, <Модель>, <Индекс>)
Вторым параметром передается ссылка на компонент-редактор, третьим - ссылка на модель, четвертым - индекс текущего элемента модели, представленный экземпляром класса QModelIndex.
Полное описание класса QAbstractItemDeiegate можно найти на странице https://doc.qt.io/qt-5/qabstractitemdelegate.html - на странице https://doc.qt.io/qt-5/qitemdelegate.html, а класса QStyledItemDelegate - на странице https://doc.qt.io/qt-5/qstyleditemdelegate.html.
На следующем шаге мы закончим изучение этого вопроса.