Qt5 и Pattern для реализации подобных диалогов

Как, на ваш взгляд, лучше всего реализовать подобные диалоги в Qt5 без дублирования кода?

Вот в чем проблема: имея две «немного разные» структуры данных со многими общими частями, реализовать два «немного разных» QDialog для обработки взаимодействия с пользователем.

У нас есть две структуры:

class DataA {
public:
  int one, two, three;
  bool x,y;
  SubdataA subA;
}

class DataB {
public:
  int one, two, three;
  bool x,y;
  SubdataB subB;
}

SubdataX — это некоторые другие структурированные данные, которые нам нужно обрабатывать в графическом интерфейсе. Два QDialog должны одинаково обрабатывать общие поля, в то время как SubdataX должен обрабатываться отдельными частями. Код также должен выполнять некоторые операции со структурами данных и предоставлять выходные файлы. Эта часть совсем легкая.

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

Спасибо.


person HappyCactus    schedule 04.03.2015    source источник
comment
Можно ли использовать полиморфизм?   -  person Tyler Jandreau    schedule 04.03.2015
comment
Это была моя первая мысль, но мне трудно управлять классом-предком (который должен быть абстрактным) и файлами пользовательского интерфейса. Но это может быть решением. Другие идеи?   -  person HappyCactus    schedule 04.03.2015


Ответы (2)


Я не уверен, что вы подразумеваете под «трудно управлять классом-предком». Кажется, я понимаю, что вы хотите, чтобы полиморфный ввод определял макет диалогового окна. Верно ли это предположение?

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

class IData {
public;
    int one, two, three;
    bool x, y;
};

class DataA : public IData {
public:
    // more data in here
};

class DataB : public IData {
public:
     // more unique data in here
}

Теперь предположим, что вы написали диалоговое окно с сигнатурой функции.

void configureDialog(IData *data) {
    DataA *dataA = dynamic_cast<DataA*>(data);
    if (dataA) {
        // configure what parts of the QDialog to see here
    }

    DataB *dataB = dynamic_cast<DataB*>(data);
    if (dataB) {
        // configure other parts of the QDialog you want to see
    }
}

Что позволило бы полиморфную конфигурацию одного блока QDialog.

person Tyler Jandreau    schedule 04.03.2015
comment
Это может быть приемлемо для структуры данных (хотя мне не очень нравится использование dynamic_cast, но это можно обойти). Но для QDialog это проблема, если только мы не используем большой универсальный класс, реализующий логику для всех типов структур. Предпочтительным был бы лучший подход ООП, поэтому использование полиморфизма также в диалогах. Проблема в том, что обработка файла ui реализована в Qt. Как объяснено здесь: qt-project.org/ doc/qt-4.8/designer-using-a-ui-file.html мы должны анализировать файл пользовательского интерфейса при сборке. Но класс ui_xxx генерируется и не может быть подклассом :-( - person HappyCactus; 04.03.2015
comment
Я все еще не вижу проблемы. Просто используйте множественное наследование, используя класс, определенный файлом пользовательского интерфейса для каждого уникального элемента данных. - person Tyler Jandreau; 04.03.2015
comment
позвольте мне повторить: класс DialogA использует dialogA.ui, который генерирует класс ui_dialogA. У класса DialogB есть похожие компаньоны. Идея состоит в том, чтобы повторно использовать большую часть кода, но файлы пользовательского интерфейса и классы нельзя использовать полиморфно. Так какую архитектуру вы предлагаете? Спасибо. - person HappyCactus; 04.03.2015
comment
... но файлы пользовательского интерфейса и классы не могут использоваться полиморфно. утверждение, которое я считаю неверным. Просмотрите qt-project.org/doc/qt-4.8/uitools- множественное наследование.html - person Tyler Jandreau; 04.03.2015
comment
Тайлер, спасибо за терпение, но не могли бы вы пояснить это? Как бы вы структурировали дерево наследования в моем примере? Спасибо за помощь. - person HappyCactus; 04.03.2015
comment
Не беспокойтесь, поэтому я решил ответить на этот вопрос. Я бы, вероятно, сделал базовую форму с дизайнером пользовательского интерфейса, которая охватывала бы большинство ваших взаимодействий (сохранение, загрузка, ок и тому подобное). Имейте в виду, что макеты и виджеты можно добавлять/удалять с помощью кода. Затем я добавлял/удалял виджеты для этого конкретного DataA или DataB QDialog, наследуя форму базового класса, определенную пользовательским интерфейсом. Я не думаю, что у вас есть вариант для чисто абстрактной интерпретации с использованием дизайнера пользовательского интерфейса. Дизайнер пользовательского интерфейса — хороший инструмент, но ему не хватает гибкости, необходимой для вашего приложения. - person Tyler Jandreau; 04.03.2015
comment
ммм... спасибо. Это решение. С другой стороны, я думал, что мы можем обойти невозможность использования наследования с классами UI_xxx, используя метапрограммирование шаблонов. Мне нужно попробовать, я поделюсь решением здесь, если оно сработает. - person HappyCactus; 04.03.2015

Как заявил Тайлер Жандро, возможным решением является использование полиморфизма.

Но это требует тщательного планирования архитектуры и наследования классов, потому что, чтобы избежать использования понижающего приведения и огромного и необслуживаемого количества случаев switch(), вам также необходимо использовать полиморфизм в классах GUI.

Как того требует архитектура View/Model, классы данных будут имитироваться классами управления/графического интерфейса.

Классы данных будут реализованы с использованием предка, абстрактного класса CommonData, который включает в себя общие «поля», и двух (или более) конкретных классов данных, полученных из CommonData посредством наследования. Моя первая идея заключалась в том, чтобы вместо этого использовать композицию, но это создало бы другие проблемы при реализации графического интерфейса.

Таким образом, DataA и DataB являются производными от CommonData.

Со стороны графического интерфейса структура аналогична, но из-за отсутствия поддержки наследования классов форм пользовательского интерфейса, сгенерированных Qt uic, мы не можем использовать наследование. Мое первое предположение состояло в том, чтобы использовать метапрограммирование шаблонов и реализовать класс-предок как класс шаблона, но, хотя это работало на стороне C++, moc отказывается анализировать этот класс и генерировать файл moc_X, когда класс с тегом Q_OBJECT является шаблоном.

Поэтому мы собираемся использовать сочетание наследования и композиции.

Это архитектура: «контейнерный» класс GUI (ContainerDialog) реализует GUI для класса CommonData; абстрактный класс PluggableInterface будет определять набор операций (мы увидим ниже); набор конкретных классов, производных от последнего, будет реализовывать логику GUI для остальных классов.

Таким образом, ContainerDialog загружает форму ContainerDialog.ui как "стандартный" QDialog и управляет всем интерфейсом с помощью CommonData. Его конструктор или сеттер получит указатель CommonData, помните, что CommonData является абстрактным и не может быть инстанцирован.

Конкретные поля управляются с помощью определенных графических компонентов, которые «подключены» к графическому интерфейсу ContainerDialog. Например, метод, определенный в PluggableInterface, будет вставлять производный компонент QWidget в графический интерфейс ContainerDialog. Задействованные классы, например, ComponentA1, ComponentA2, ComponentB и т.д....

Использование абстрактного интерфейса PluggableInterface и компонентов пользовательского интерфейса не позволит ContainerDialog узнать, какой тип конкретного класса используется, и весь необходимый код для создания экземпляров конкретных классов может быть реализован с использованием некоторого шаблона создания (абстрактная фабрика, прототипы и т. д.). ...)

person HappyCactus    schedule 05.03.2015