【问题标题】:Concept of and basic questions about separating logic (C++) and GUI (Qt)关于分离逻辑 (C++) 和 GUI (Qt) 的概念和基本问题
【发布时间】:2014-09-25 19:15:21
【问题描述】:

我在C++ 完成了一个项目。它是一个控制台应用程序,使用 CodeBlocks 创建。尽管我认为它在这个问题的范围内并不那么重要:该应用程序管理有关小公司的账单和客户的数据。该程序是完整的,可以通过控制台用户界面非常容易地扩展(现在,我以程序员的身份运行它)。

现在我决定使用Qt 和带有 QtDesigner 的 QtCreator 来学习 GUI 编程!

不仅因为在创建 GUI 应用程序时将逻辑与 GUI 分离是常见的做法,我想将我的项目分为两大部分来实践,当然,即 逻辑图形界面。 你已经知道逻辑部分是完整的;我拥有的是一个名为project 的项目文件夹,其中包含另一个文件夹(CodeBlocks 项目)project_logic,它再次包含几个类,因此包含头文件和实现文件(以及一个主文件,最终当然会过时)。它还包含程序读取/写入的文件。它是用“纯”C++ 编写的,none 使用了Qt 提供的方式,对我来说重要的是它保持这种方式

现在我在project文件夹中添加了一个Qt项目project_gui并开始创建GUI,只实现最基本的功能,比如在对话之间切换,关闭应用程序等。到目前为止它知道没有关于它未来的后端 (project_logic)。

作为第三个组件,我需要某种控制,它将应用程序的逻辑与其GUI 联系起来。这是我的概念性问题:将它们放在一个应用程序中的最佳方法是什么?

建议

  1. 由于project_logic 可以单独作为控制台应用程序工作,它已经提供了最基本的控制组件和功能。这将保持这种状态,因为我想保留它的独立功能。更是如此,因为我对 GUI 编程完全陌生和/或在两周内我可能会碰巧为相同的逻辑创建另一个 GUI。结果将是逻辑部分的类像任何其他标题一样包含在 GUI 源代码中,并用于创建具有完整功能的程序。验证用户输入将依赖于 GUI 部分。程序的逻辑在任何情况下都可以更新。

  2. 使 GUI 尽可能可重用;我是否应该实现第三个组件 à la project_controlling,它提供 GUI 和逻辑之间的交互(通过控制完成的用户输入验证),因为这两者中的每一个都尽可能地保持独立? GUI不包括逻辑头,可以说,但包括控制头?


我承认,第二点听起来有点奇怪;简而言之,我的目标是:

  • 保持project_logic 标准C++独立(在修补、添加功能等方面...)和
  • Qt 用于 GUI,最大限度地(同时合理地)分离 GUI 和逻辑。

思路

  1. 我应该通过#include "../project_logic/header1.h" 等包含project_logic 标头吗? (使用类可能会出现问题,我将在单独的问题中发布。)

  2. 我应该将它们作为子项目包含进来吗?

  3. 如何“在代码中”连接部件?

  4. 逻辑函数还能找到我前面提到的文件(读/写)吗?


请记住以下几点:我是 GUI 编程的新手! 我尽力解释了我的想法/问题...但是,我知道 C 和 C++ 并编写控制台应用程序我用于例如我认为,在大学进行模拟并且可以很好地处理标准的东西。即使潜在的回答者感觉想提出一种非常不同的方法,我也会感谢我提出的概念的“解决方案”。我在介绍中解释了原因。不用说,我当然有兴趣听到不同的建议。

在我做了一些研究并以“试错”方式尽力而为之后,我决定发布这个问题。 StackOverflow 和其他板上有很多关于这个主题的信息,所以我想提出我的想法并收集批评和意见,而不是添加另一个“如何做?”问题的大杂烩。

由于这个问题是关于一般方法的,我可能会(非常肯定... :-P )稍后提出更多技术问题,一旦出现,我想将其编辑到这个问题(超链接)中。 但是,如果有这方面的基本食谱,当然是受欢迎的。


在一些 cmets 和答案之后,我想发布一点 EDIT 来说明一下:

逻辑当前状态

  • project_logic 或多或少已完成并在 CodeBlocks 中编码为 CodeBlocks 项目。
  • 可以作为带有“控制台用户界面”的控制台应用程序工作。 (它有一个main.cpp,现在只用于调试。)
  • 其组件尽可能地划分为类(头文件和 cpp 实现文件)。

GUI的当前状态

  • project_gui 正在设置为 Qt-Widget-Application 项目(使用 QtCreator/Designer)。
  • 到目前为止,只是 GUI,仅此而已(与 project_logic 没有任何联系)。

目标和...

...工作流程,我想遵循,因为这是我的第一个大项目:

  • project_logicproject_gui 不会离开各自的目录;它们都在一个名为project 的目录中。 (例外:逻辑将导出为 dll(或类似的东西)如有必要,然后提供给 GUI。)
  • 如果 project_logic 中有要更改的内容,我想在 CodeBlocks 中进行更改(并重复上述可能的导出)。
  • project_logic(或任何第三层,例如project_controlling)必须以最简单的方式为project_gui 一次性使用......(参见Trains of thinking number 1):-P

【问题讨论】:

  • 还有“你好,StackOverflow!” :-)
  • 我想@我的link to another question,它还涉及项目的设置和结构(实际上是这个项目)。对于在设置他们的第一个 Qt 项目的过程中问自己相同问题的用户来说,它可能很有用。

标签: c++ qt user-interface separation-of-concerns conceptual


【解决方案1】:
  • 如果您有单独的项目

当您在不同项目中开发应用程序的不同部分时,最简单的方法是将主项目与库链接并使用它们。因此,在您的情况下,您应该为您的 Qt 项目提供在 CodeBlocks 中开发和编译的项目逻辑的 dll,链接到它并使用这些类。

例如,您可以将库的头文件放在名为Logic 的文件夹中,将.lib 文件的调试和发布版本放在相关文件夹中并链接您的应用程序:

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/Logic/release/ -lLogic
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/Logic/debug/ -lLogic

INCLUDEPATH += $$PWD/Logic
DEPENDPATH += $$PWD/Logic
  • 如果您在一个 Qt 项目中拥有所有内容

在这种情况下,使用Subdirs 将代码模块彼此分开是个好主意。这样您就可以拥有可重用且易于更改的独立软件模块。它还使项目更简洁、更易于阅读。

在这种方法中,模块可以通过信号和插槽相互交互,这使得不同的组件完全独立,改变一个模块不需要改变其他部分。

Qt Creator 提供了很好的自动化,可以让各个部分相互喜欢。您可以创建一个 Subdirs 项目并将您的子项目添加到其 .pro 文件中:

TEMPLATE = subdirs

CONFIG += ordered

SUBDIRS += \
    Component1 \
    Component2 \
    Component3 \
    MainApp \

您应该将其他人依赖的子项目放在列表的首位。另请注意,子项目的 .pro 文件的名称应与其文件夹名称相同。这样子项目就会被检测到并列在“项目”窗格中。

子项目Component1Component2Component3 可以是库。 Component1 的 .pro 文件的一部分:

TARGET = Component1
TEMPLATE = lib

DEFINES += COMPONENT1_LIBRARY

SOURCES += ...
HEADERS += ...

子项目MainApp可以是app。 MainApp 的 .pro 文件的一部分:

TARGET = MainApp
TEMPLATE = app

您可以通过将每个子项目链接到子项目来使用每个子项目中的库。这可以通过右键单击子项目并选择“添加库”然后选择“内部库”来完成。当您从子项目列表中选择一个库时,链接配置会自动添加到 .pro 中。会是这样的:

win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../Component1/release/ -lComponent1
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../Component1/debug/ -lComponent1
else:unix: LIBS += -L$$OUT_PWD/../Component1/ -lComponent1

INCLUDEPATH += $$PWD/../Component1
DEPENDPATH += $$PWD/../Component1

【讨论】:

  • 主应用程序(GUI?)也只是一个子项目?我不能将项目逻辑放入 dll 中,然后将其包含到我现有的 GUI-Qt 项目中吗?为什么要绕道子项目? --- 有没有简单的方法告诉我的程序“在这个特定的文件夹中,你可以找到一个 .h 和一个 .cpp 文件,使用它!”而不使这些文件成为 GUI 项目本身的一部分?无论是 dll、依赖项还是其他... ^^ 还是您刚才所描述的,对不起... xD
  • 逻辑和 GUI 都存在,在我的完美世界中,我只是告诉 Qt-GUI-project 存在它应该使用的逻辑类的头文件和 cpp 文件。
  • @LCsa MainApp 也是一个可以有 GUI(例如 MainWindow 和其他对话框)的子项目。这样,lib 类型的所有子项目都将成为 Windows 中的 dll。这种方式可以帮助您将项目分解为一些可重复使用的小部分。当然你也可以避免这种逻辑,在文件夹的不同类中有不同的组件。但是使用子项目会使您的项目干净整洁。您还可以从 QtCreator 为您提供的子目录自动化中受益。毕竟这种方法是以定义明确的方式将库(例如 dll)放在不同的文件夹中。
  • 请问:如果我有我的程序逻辑的所有类的 dll,将这个 dll 包含到 GUI 部分(Qt 项目)不是最简单的方法吗?现在我想在 CodeBlocks 中开发逻辑(更新它),并且只将它提供给 GUI(使用 Qt 创建)。
  • 我在我的问题中附加了一个编辑部分,尽可能简洁地总结所有内容。如果问题变得令人困惑或“太大”,我很抱歉,但是我尽力提供所有需要的信息并使其对其他人也很有趣(因为它很笼统)。您的帖子很有帮助,但我很乐意按照我在原始帖子中编辑的内容进行工作(我希望它会在一开始就出现)。而且你的方法感觉不像是“最简单的”——如果我错了,请纠正我。在我的问题中,我旨在展示我的工作流程,收集对未来项目的批评并帮助继续进行。
【解决方案2】:

欢迎来到 SO。

您确实在这里将两三个问题捆绑在一起,但让我们试一试:

作为第三个组件,我需要某种控制链接 应用程序的逻辑及其 GUI。

由于您使用的是 Qt,因此您对这个问题有一个内置的答案:

Qt Project-Model/View Programming。为了让您开始:

模型/视图架构

Model-View-Controller (MVC) 是一种设计模式,起源于 Smalltalk 在构建用户界面时经常使用。在设计 模式,伽玛等。写:

MVC 由三种对象组成。模型是应用程序 对象,视图是它的屏幕呈现,控制器 定义用户界面对用户输入的反应方式。在 MVC 之前, 用户界面设计倾向于将这些对象集中在一起。 MVC 将它们解耦以提高灵活性和重用性。

如果视图和控制器对象结合起来,结果是 模型/视图架构。这仍然将数据的方式分开 从它呈现给用户的方式存储,但提供了一个 基于相同原理的更简单的框架。这种分离使 可以在几个不同的视图中显示相同的数据,并且 实现新类型的视图,而不改变底层数据 结构。为了允许灵活处理用户输入,我们引入了 代表的概念。在这方面有一个代表的好处 框架是它允许数据项的呈现方式和 编辑为自定义。

由 QT 框架明确支持的 MVC 模型(也可以与其他 GUI 框架一起实现,尽管需要做更多的工作),被广泛接受为一组健壮、灵活的设计模式,可以管理和分离各种应用程序层,以您正在考虑的方式 - 所以您走在正确的轨道上。

我承认,第二点听起来有点奇怪;把它 简而言之,我的目标是……

如何设置您的源代码项目的问题实际上与您的应用程序架构本身无关,尽管这些领域通常是相交的,因此良好的项目组织有助于更轻松地实施您的架构,反之亦然。您如何组织您的项目及其各种库和类可能不仅取决于您现在正在处理的项目,还取决于未来项目的计划。例如,正如您所提到的,您可能想要设计可用于多个不同应用程序的某些 GUI 组件。如果是这样,您可能希望将您的 GUI 模块放入一个可被许多应用程序使用的单独的可重用通用库中。

但是,某些规则适用于所有领域,并且大多数有经验的开发人员都遵循 - 这里有一些重要的,还有更多:

  • 每个单元的一个主要类及其朋友类(hpp/cpp 文件)。

  • 要非常小心包含在头文件中的内容以及留给 CPP 文件的内容。你会找到 此处有关 SO 的指南以及有关此主题的任何优秀 C++ 书籍,即 非常重要,尤其是在复杂的项目中。 (从声音 它 - 例如您关于如何使用#include 和“连接部件”的问题 “在代码中 - 你需要更好地掌握一些基础知识 C++ 编程。那里有一些优秀的书籍 - 你可以找到 在这里列出。 C++ Primer (5th Edition) 是最好的起点之一。)

  • 根据它们的类别分解您的类和库 功能。大多数 IDES 支持项目中的虚拟子文件夹 (不确定 Code::Blocks)以帮助保持这样的组织 方式。这实际上涉及基本的设计问题,而不是 只是如何在项目中布置代码。

  • 避免 tight coupling!

    在软件工程中,耦合或依赖是 每个程序模块都依赖于其他模块。

    耦合通常与内聚形成对比。经常低耦合 与高内聚相关,反之亦然。低耦合通常是 结构良好的计算机系统和良好设计的标志,以及何时 结合高凝聚力,支持高的总体目标 可读性和可维护性。

  • 充分利用namespaces,这是另一个有助于保持模块化和组织化的语言功能。

在您的情况下,您可能想要做的是将“应用程序逻辑”打包到一个库中,将通用 GUI 模块打包到第二个库中,然后是第三个瘦可执行文件 - 可能只包含 main() 和一个几行代码启动并在完成后关闭它们——启动 Qt 应用程序并初始化库中的类,这些类使用 MVC 模型进行交互并执行应用程序的实际工作。三个单独的模块不是必需的,尽管这样会更“通用”和可重用”并且更容易保持组织。

您确实已经通过这个问题触及了各种各样的主题,而且,其中一些主题与 C++ 编程基础有关,而不仅仅是“将应用程序逻辑与 GUI 分离”。希望这个答案能帮助您朝着正确的方向前进。

重要提示: GUI 编程是一个完整且不是特别简单的编程分支。有 GUI 专家,也有只使用 GUI 最少的程序员。 (我是后者中的一员)。有一个名为 User Experience 的 SE 站点,虽然它本身不涉及 GUI 编程,但它涉及用户如何与系统交互,这与 GUI 编程技术直接相关。所以,当你说“现在我决定学习 GUI 编程”时,要知道你正在从事一项大工作。如果您对使 GUI 编程成为您的专长并不真正感兴趣,您可能需要考虑使用向导和预制 GUI 解决方案,而不是全部手动完成。 QtCreator 确实提供了一些这样的支持,Code::Blocks 也是如此。如果您打算开展这项严肃的业务,也有可用的商业框架。除非您只是为了学习而这样做,否则不建议在严肃的商业编程工作中重新发明轮子。

【讨论】:

  • 实际上,在发布问题之前,我已经开始阅读这篇模型/视图文章。虽然它肯定是一个非常强大的机制,但我想在第一个项目中坚持更基本的手段。我想以“最简单”的方式包含project_logic 源,因为我可以处理标准的C++(并且该项目的范围不需要任何更高级的东西)。即使这种方法可能不是超级简洁;因为我想使用 QtDesigner 处理 GUI 的下一个新事物(我在帖子中没有提到;GUI 编程本身是另一项业务,我知道。;-))
  • 同时使用两个新概念实在是太过分了,根本无法理解其中任何一个。
  • @LCsa:IMO 最重要的概念是松散耦合,它适用于所有编程——如果你刻意专注于解耦你的函数和模块,事情往往会自然而然地出现——自然边界变得突出。另外,我个人有一个规则(不是 ironclad),如果我要在一个函数中使用超过 3 个参数或 10 行,我可能会耦合和捆绑东西,是时候重新考虑方法。在 C++ 中,正确设置头文件、源文件和命名空间对于实现所有类型的模块化和分离大有帮助。
  • 至于你的答案的第二部分:所有模块已经完全分开了。有一个客户类,一个项目类,一个账单类(它有客户和项目作为成员),还有一个控制类,负责通信和控制。所有这些都在单独的单元中,并且独立(尽可能地参见账单类别);创建一个新的控件类可以以不同的方式使用其他类。我试图在介绍中强调我的项目的这种状态。标题问题旨在了解是否还有其他事情要做...
  • ...只是将我的模块包含在 GUI 代码中,以使其功能完全一次性。如果这很好用(也许这里的第二个答案会导致这条小巷......)我也可以将薄控制层包含到 GUI 中(以同样的方式我会包含逻辑)并让它承担一部分控制/通讯。我想这会使 GUI 更易于重用,因为没有“逻辑东西在 GUI 中硬编码”,如果你知道我想说什么的话。
猜你喜欢
  • 2019-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 2017-10-20
  • 1970-01-01
相关资源
最近更新 更多