Подземелья Qt: Рецепты приготовления монстров (Часть 1. Редактирование разнородных данных)

в 10:35, , рубрики: c++, qt

image

Всякому профессиональному разработчику приложений, использующему Qt, довольно часто приходится использовать связку model/delegate/view для различных манипуляций с данными. Основные детали этого шаблона хорошо описаны в стандартном руководстве на эту тему, однако, часто приходится сталкиваться с ситуацией, когда стандартное поведение необходимо расширить или дополнить под конкретные нужды. Обычно, тут и начинается то, за что мы все любим программирование — поездка на любимых самокатах и рикшах — придумывается собственное решение. Именно в этот момент внутренний голос должен бы нас остановить, но мы ловко парируем: «Я уже смотрел, документации много — читать долго, сроки поджимают и еще масса других дел. А главное, не ясно откуда начинать искать». Именно поэтому, любой уважающий себя разработчик должен иметь под рукой собственноручно собранные и опробованные рецепты и стараться пополнять свою коллекцию.

Постановка задачи

Создадим черновик простого редактора разнородных данных на основе QAbstractTableModel и добавим пользовательский тип evilType (да-да, именно этот тип требует дополнительных ухищрений).

Как правило, у этой задачи есть два решения:

  1. Переопределить функцию createEditor у QAbstractItemDelegate или его производных
  2. Добавить собственный редактор для пользовательского типа и переопределить стандартную фабрику редакторов 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

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js