【问题标题】:Qt5 and Pattern for similar dialogs implementation用于类似对话框实现的 Qt5 和 Pattern
【发布时间】:2015-05-05 18:08:57
【问题描述】:

您认为在 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 是我们需要在 GUI 中处理的其他一些结构化数据。两个 QDialog 应该以相同的方式处理公共字段,而 SubdataX 必须由特定部分处理。代码还应该对数据结构进行一些操作,并提供输出文件。这部分很简单。

我的问题是,实现这一点的最佳策略是什么?目标是拥有优雅的代码,应该很容易维护并且尽可能地可读。框架是Qt,所以应该在UI文件中使用qdialog布局为Qt量身定制解决方案,因为gui布局太复杂,无法通过代码设计。

谢谢。

【问题讨论】:

  • 能用多态吗?
  • 这是我的第一个想法,但我发现很难管理祖先类(应该是抽象的)和 ui 文件。但这可能是一个解决方案。其他想法?

标签: c++ qt oop design-patterns ooad


【解决方案1】:

我不确定您所说的“难以管理祖先类”是什么意思。我想我理解你想要一个多态输入来确定对话框的布局。这个假设正确吗?

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

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

【讨论】:

  • 这对于数据结构来说可能是可以接受的(虽然我不太喜欢使用dynamic_cast,但这可以解决)。但是对于 QDialog 来说这是一个问题,除非我们使用实现所有类型结构的逻辑的“big do-all”类。更好的 OOP 方法将是首选,因此在对话上也使用多态性。问题在于 ui 文件处理是在 Qt 中实现的。正如这里所解释的:qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html 我们必须在构建时解析 UI 文件。但是生成了ui_xxx类,不能子类化:-(
  • 我仍然看不到问题所在。只需使用 UI 文件为每个唯一数据项定义的类使用多重继承。
  • 让我重申一下:DialogA 类使用生成类 ui_dialogA 的 dialogA.ui。 DialogB 类有类似的同伴。这个想法是重用大部分代码,但不能多态地使用 ui 文件和类。那么你建议的架构是什么?谢谢。
  • "...但是 ui 文件和类不能多态使用。"是我认为不正确的陈述。请查看qt-project.org/doc/qt-4.8/uitools-multipleinheritance.html
  • 别担心,这就是我决定回答这个问题的原因。我可能会与 UI 设计器一起制作一个基本表单,涵盖您的大部分交互(保存、加载、好的,诸如此类)。请记住,可以通过代码更改布局和添加/减去小部件。然后,我将通过继承 UI 定义的基类表单为特定的 DataA 或 DataB QDialog 添加/删除小部件。对于使用 UI 设计器的纯粹抽象解释,我认为您没有选择权。 UI 设计器是一个很好的工具,但缺乏应用程序所需的灵活性。
【解决方案2】:

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

但这需要仔细规划架构和类继承,因为要避免使用向下转换和大量且无法维护的 switch() 情况,您还需要在 GUI 类上使用多态性。

根据视图/模型架构的要求,数据类将被控件/GUI 类模仿。

数据类将使用包含公共“字段”的祖先抽象类CommonData 和通过继承从CommonData 派生的两个(或更多)具体数据类来实现。我的第一个想法是改用合成,但这会在实现 gui 时带来其他问题。

所以DataADataB 派生自CommonData

在 Gui 方面,结构类似,但是由于 Qt 的uic 生成的 UI 表单类缺乏继承支持,我们不能使用继承。我的第一个猜测是使用模板元编程,并将祖先类实现为模板类,但尽管它在 C++ 端工作,moc 拒绝解析该类并在Q_OBJECT 标记类时生成moc_X 文件是一个模板。

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

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

所以ContainerDialog 加载ContainerDialog.ui 表单作为“标准”QDialog,并使用CommonData 管理所有接口。他的构造函数,或者setter会收到一个CommonData指针,记住CommonData是抽象的,不能被实例化。

通过“插入”在 ContainerDialog gui 中的特定图形组件来管理特定字段。例如,PluggableInterface 中定义的方法将在 ContainerDialog gui 中插入 QWidget 派生组件。所涉及的类例如有ComponentA1ComponentA2ComponentB等……

抽象接口PluggableInterface和UI组件的使用将阻止ContainerDialog知道正在使用什么样的具体类,并且实例化特定类的所有必要代码都可以使用一些创建模式来实现(抽象工厂、原型等)

【讨论】:

    猜你喜欢
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 2012-01-30
    相关资源
    最近更新 更多