用于类似对话框实现的 Qt5 和 Pattern

Qt5 and Pattern for similar dialogs implementation

您认为在不重复代码的情况下在 Qt5 中实现类似对话框的最佳方式是什么?

这就是问题所在:有两个 "slightly different" 数据结构,有许多公共部分,实现两个 "slightly different" 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是我们在GUI中需要处理的其他一些结构化数据。两个QDialog对公共字段的处理应该是一样的,而SubdataX则必须由特定的部分来处理。代码还应该对数据结构进行一些操作,并提供输出文件。这部分很简单。

我的问题是,实现这个的最佳策略是什么? objective 是为了拥有优雅的代码,应该很容易维护,并且尽可能具有最高的可读性。框架是Qt,所以解决方案应该在UI文件中使用qdialog布局针对Qt进行定制,因为gui布局太复杂而无法通过代码设计。

谢谢。

我不确定 "difficult to manage the ancestor class" 是什么意思。我想我明白你想要一个多态输入来确定对话框的布局。这个假设正确吗?

例如,给定以下 类,您可以使用动态转换来影响对话框的行为。

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 框的多态配置。

正如 Tyler Jandreau 所说,一种可能的解决方案是使用多态性。

但这需要仔细规划体系结构和 class 继承,因为要避免使用向下转换和大量无法维护的 switch() 情况,您还需要在 GUI classes.

根据 View/Model 体系结构的要求,数据 classes 将被 control/Gui classes 模仿。

数据 classes 将使用祖先、抽象 class CommonData 实现,其中包括公共 "fields" 和两个(或更多)具体数据 classes 通过继承从 CommonData 派生。我的第一个想法是改用组合,但这会在实现 gui 时带来其他问题。

所以DataADataB是从CommonData推导出来的。

在 Gui 方面,结构类似,但是由于缺少对 Qt 的 uic 生成的 UI 形式 classes 的继承支持,我们无法使用继承。我的第一个猜测是使用模板元编程,并将祖先 class 作为模板 class 实现,但尽管它在 C++ 端有效,moc 拒绝解析 class并在标记为 class 的 Q_OBJECT 是模板时生成 moc_X 文件。

所以我们将混合使用继承和组合。

这是架构:"container" GUI class (ContainerDialog) 为 CommonData [实现了 GUI class; PluggableInterface 抽象 class 将定义一组操作(我们将在下面看到);从后者派生的一组具体 classes 将为其余 classes 实现 GUI 逻辑。

因此 ContainerDialogContainerDialog.ui 表单加载为 "standard" QDialog,并使用 CommonData 管理所有界面。他的构造函数,或者说一个setter会收到一个CommonData指针,记住CommonData是抽象的,不能实例化。

特定字段通过 ContainerDialog gui 中 "plugged" 的特定图形组件进行管理。例如,在 PluggableInterface 中定义的方法将在 ContainerDialog gui 中插入 QWidget 派生组件。涉及的class例如ComponentA1ComponentA2ComponentB等...

抽象接口 PluggableInterface 和 UI 组件的使用将阻止 ContainerDialog 知道正在使用哪种具体 class,以及所有实例化特定 classes 的必要代码可以使用一些创建模式(抽象工厂、原型等...)