逻辑(c++)与GUI (Qt)分离的概念及基本问题



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

现在我决定学习GUI编程使用Qt和QtCreator与它的QtDesigner!

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

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

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

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

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


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

  • 保持project_logic标准C++独立(在补丁,添加功能等方面)和
  • 在最大限度(同时合理)分离GUI和逻辑的情况下使用Qt进行GUI。

思路

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

  2. 我应该包括他们作为一个子项目吗?

  3. 我如何"在代码中"连接部件?

  4. 逻辑功能仍然找到我之前提到的文件(读/写)吗?


请记住以下内容:我是GUI编程的新手!我尽力解释我的想法/问题…然而,我知道C和c++,并编写了用于大学模拟的控制台应用程序,我认为我可以很好地处理标准内容。即使潜在的回答者想要提出一个非常不同的方法,我也会感谢我所提出的概念的"解决方案"。原因我在引言中已经解释过了。我当然很想听听不同的建议,这一点不必多说。

在我做了一些研究并尽我最大的努力之后,我决定发布这个问题。错误"时尚之前。在StackOverflow和其他论坛上有很多关于这个主题的信息,所以我想提出我的想法,收集批评和意见,而不是在问题的大杂烩中添加另一个"如何?"。

既然这个问题是关于一般方法的,我可能会(相当肯定)……:-P)以后再问更多的技术问题,我想把它们一出现就编辑到这个问题(超链接)中。但是,如果有基本的方法,当然是受欢迎的。


在一些评论和回答之后,我想发布一个小编辑,只是为了让事情更清楚:

逻辑当前状态

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

GUI当前状态

  • project_gui正在被设置为Qt-Widget-Application项目(使用QtCreator/Designer)。
  • 到目前为止,它是只有GUI,没有更多的(没有连接到project_logic以任何方式)。

Aims and…

…<工作流/strong>因为这是我的第一个大项目,所以我想跟着做:

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

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

例如,你可以把库的头文件放在名为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文件的名称应该与其文件夹名称相同。这样就可以检测子项目,并在Projects窗格中列出子项目。

子项目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

欢迎来到SO。

你确实把两三个问题捆绑在一起了,但让我们试一试:

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

因为你正在使用Qt,你有一个内置的答案这个问题:

Qt Project-Model/View Programming。让你开始:

模型/视图体系结构

模型-视图-控制器(MVC)是一种设计模式,起源于在构建用户界面时经常使用的Smalltalk。在设计pattern, Gamma et al. write:

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

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

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

我承认,第二点可能听起来有点奇怪;这么说吧总之,我的目标是……

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

某些规则,然而,适用于所有的,并遵循大多数有经验的开发人员-这里有几个大的,还有更多:

  • 每个单元一个主类和它的友类(hpp/cpp文件)

  • 对于头文件中包含的内容和留给CPP文件的内容要非常小心。你会发现这里有关于SO的指导方针,任何关于这个主题的优秀c++书籍中都有,这是非常重要,特别是在复杂的项目中。(来自……的声音它-例如您关于如何使用#include和"连接部件"的问题——你需要更好地掌握一些基础知识c++编程的基础。你可以找到一些优秀的书列表在这里。c++入门(5版)是最好的起点之一

  • 将类和库按其功能。大多数ide都支持项目中的虚拟子文件夹(不确定代码::块),以帮助保持这样的组织的方式。这实际上涉及到基本的设计问题仅仅是如何在项目中布局代码。

  • 避免
  • 紧密耦合!

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

    耦合通常与内聚相对立。低耦合与高内聚相关,反之亦然。低耦合通常是一个问题一个结构良好的计算机系统和一个好的设计的标志,当结合高凝聚力,支持高总目标可读性和可维护性。

  • 善用命名空间这是另一个很棒的语言特性,它有助于保持事物的模块化和组织化。

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

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

重要提示:GUI编程是编程的一个完整且不太容易的分支。有GUI专家,也有极少使用GUI的程序员。(我属于后一种人)。有一个叫做用户体验的SE网站,虽然它不处理GUI编程本质上,处理用户如何与系统交互,这与GUI编程技术直接相关。所以,当你说"现在我决定学习GUI编程"时,要知道你正在承担一项艰巨的任务。如果您对GUI编程不是很感兴趣,那么您可能需要考虑使用Wizards和预制GUI解决方案,而不是全部手工完成。QtCreator提供了一些这样的支持,Code::Blocks也是如此。如果您打算做这个严肃的业务,也有一些商业框架可用。除非你只是为了学习而这样做,否则不建议在严肃的商业编程工作中重新发明轮子。

最新更新