那么怎么实践它呢?于是我在一个项目中设计了将各个功能的界面保存在其自己的模块中的方式。
使用Qt编写模块化插件式应用程序_flyoxs的专栏-CSDN博客
简而言之,.lib称为导入库,相当于头文件;.dll是动态库文件,相当于cpp,头文件中函数的具体实现。
一般只有头文件而忘记引用动态库会提示“函数未定义”,反之会提示“未知符号”
全局定义信号槽类别,每个模块有一个对外接口对象,仅仅连接每个对象的信号槽就可以解决需要连接繁多的信号槽的矛盾(非基础类型的特定类型参数的需要进行单独连接)
将每个模块设置为生成动态库(而非应用),指定生成位置
软件主模块包含所有模块的头文件(声明定义),引用每个模块的动态库(具体实现),然后连接各个模块的信号槽。
最后进行总体的编译。
优点:
将编译过程局限于模块内,例如含有海图的软件编译时间较长,将其封装为模块可以做到在其没有改变的情况下省去这个模块的编译时间。节省编译时间便于从“子项目”项目向“一个项目”转化。
现有问题:
仍不够熟练在编译时容易出现难以解决的错误。
对于结构体数据仍然需要不断修改,难以一劳永逸。所以十分固定的稳定功能,模块化才有意义。
信号槽连接比直接函数调用慢,模块间不应存在频繁调用。
Windows、linux切换时配置有些不同。
1.主模块设置
左侧画红线的都是需要注意的设置,这里由于篇幅就补逐一截图了,反正都是碰到过坑的地方(写字是因为windows自带的截图快捷键没有编辑文字功能……)
2.辅助模块设置
除了主模块上述引用,还有生成需要是动态库类型
总结一下:生成设置、引用设置、依赖路径设置、动态库引用设置、调试设置
顺便说一句,【C/C++】【链接器】这两个地方的所有设置都是给MSVC编译器的命令行添加参数而已,这个“命令行”才是最终目的,给链接器提供完整的编译命令。
比如下图是主模块的连接器的命令行,标出的"/NOLOGO"就是主模块截图中,链接器->常规->【取消显示启动版权标志 是(/NOLOGO)】中提供的参数。
另:windows vs+qt插件下子项目的方法
动态库设置的官方参考文档:
Compiler Options Listed by Category | Microsoft Docs
如果是windows下需要在相应主模块头文件注意加上如下宏定义,并且在vs的设置中加上相应宏定义(以下的意思是如果定义了则为编译库,否则是引用库)
#ifdef TESTWIDGET_LIB
# define TESTWIDGET_EXPORT __declspec(dllexport)
#else
# define TESTWIDGET_EXPORT __declspec(dllimport)
#endif
注意模块的定义尽量合理,否则太多会让人抓狂,尽量高内聚,因为信号槽传递会比正常调用慢
还有模块内的引入其他头文件尽量是通文件夹的相对路径,否则主模块需要引入的文件夹会非常多。
我就不班门弄斧了,仅做如上几个关键点的截图。补充详见上面的那个微软vs的官方文档,各种斜杠参数都写得清清楚楚.
在子项目的项目中pro文件中会出现相应的文件夹引入
在新建的子项目中可以有“Qt Widget Application”,这样就可以联同界面一同开发(一种惯例是所有带有界面的放到主模块下,其他的均以动态库形式)
子项目的TEMPLATE 从APP改为LIB
留一个主界面的模块为APP,并且保留main.cpp,其他模块的main.cpp删掉
然后就是开发各个子模块(看到有人后缀pri的,我不太清楚是怎么回事)
块内的引入其他头文件尽量是通文件夹的相对路径,否则主模块需要引入的文件夹会非常多。
在主界面的那个模块引入各个模块,并连接各个信号槽
(自己想到的小技巧:将每个模块留一个对外接口模块cpp,并留统一且通用的信号槽【第一个参数是int可以在全局枚举,第二个参数是char*可以传输1个参数数据,然后在自己的槽中依据第一个参数的全局枚举来分拣执行相应的操作】)这样可以充分利用信号槽。
主模块需要引入各个模块的文件夹路径,动态库。
编译会出现各种问题,但一般流程不变:qmake、重新构建、执行或调试