Всякому профессиональному разработчику приложений, использующему Qt, довольно часто приходится использовать связку model/delegate/view для различных манипуляций с данными. Основные детали этого шаблона хорошо описаны в стандартном руководстве на эту тему, однако, часто приходится сталкиваться с ситуацией, когда стандартное поведение необходимо расширить или дополнить под конкретные нужды. Обычно, тут и начинается то, за что мы все любим программирование — поездка на любимых самокатах и рикшах — придумывается собственное решение. Именно в этот момент внутренний голос должен бы нас остановить, но мы ловко парируем: «Я уже смотрел, документации много — читать долго, сроки поджимают и еще масса других дел. А главное, не ясно откуда начинать искать». Именно поэтому, любой уважающий себя разработчик должен иметь под рукой собственноручно собранные и опробованные рецепты и стараться пополнять свою коллекцию.
Постановка задачи
Создадим черновик простого редактора разнородных данных на основе QAbstractTableModel и добавим пользовательский тип evilType (да-да, именно этот тип требует дополнительных ухищрений).
Как правило, у этой задачи есть два решения:
- Переопределить функцию createEditor у QAbstractItemDelegate или его производных
- Добавить собственный редактор для пользовательского типа и переопределить стандартную фабрику редакторов QDefaultItemEditorFactory
Минусы первого подхода состоят в том, что если у нас несколько видов и делегатов к ним, что, как правило, и есть в случае мало-мальски сложной программы, то нужно дублировать код createEditor для различных делегатов.
Минусы второго подхода — переопределение стандартной фабрики редакторов ведет к потере фабрики QDefaultItemEditorFactory и, соответственно, необходимости повторной регистрации стандартных редакторов в нашей фабрике.
Наш самокат
Гибридный класс, содержащий в себе стандартную фабрику и переопределяющий createEditor для пользовательских типов.
void overrideEditorFactory(void)
{
class OverridenEditorFactory : public QItemEditorFactory
{
public:
explicit OverridenEditorFactory(const QItemEditorFactory* dFactory)
: _dFactory(dFactory)
{
auto creator = new QStandardItemEditorCreator<EvilTypeEditor>();
const auto evilTypeID = QVariant::fromValue(evilType()).userType();
registerEditor(evilTypeID, creator);
}
QWidget* createEditor(int userType, QWidget *parent) const
{
const auto evilTypeID = QVariant::fromValue(evilType()).userType();
if(evilTypeID == userType)
{
return QItemEditorFactory::createEditor(userType, parent);
}
return _dFactory->createEditor(userType, parent);
}
private:
const QItemEditorFactory* _dFactory;
};
QItemEditorFactory::setDefaultFactory(new OverridenEditorFactory(QItemEditorFactory::defaultFactory()));
}
Таким образом, перед использованием нужно вызвать функцию переопределяющую стандартную фабрику. И теперь пользовательский тип везде будет редактироваться согласно наших пожеланий.
Заключение
Код в основном иллюстративный, поэтому отдельные моменты можно улучшить. но основной подход — минимализм кода и легкость масштабирования на множество отображений при использовании различных делегатов сохранена.
Полный код проекта на github.
Автор: xseven