对于一个大型系统,如何保证可扩展性和可维护性是十分重要的。Qt为我们提供了一套插件系统,能够较好的解决扩展性的问题。但是在将插件系统与信号槽机制相结合的过程中,也遇到了一些问题。经过一番探索之后总算成功了,这里写一个小小的教程,供有需要的同学查阅。
一、概述
Qt的插件系统分为High-Level API接口和Low-Level API接口。
所谓High-Level API 是指通过继承Qt为我们提供的特定的插件基类,然后实现一些虚函数、添加需要的宏即可。该种插件开发方式主要是用来扩展Qt库本身的功能,比如自定义数据库驱动、图片格式、文本编码、自定义样式等。而我们为自己的应用程序编写插件来扩展其功能时主要使用第二种方式,即Low-Level API 的方式,该方式不仅能扩展我们自己的应用程序,同样也能像High-Level API 那样用来扩展Qt本身的功能。
在本文中,我们使用Low-Level API接口进行插件的编写。有关High-Level相关内容,参阅Qt官方说明文档。
除此之外,插件还有静态和动态之分。静态插件顾名思义,就是编译出一个lib作为插件,在程序中静态编译。动态插件则是一个dll(windows下),方便扩展和维护。因此我们使用动态插件作为说明。
总的来说,插件扩展并使用信号槽机制需要以下步骤:
- 定义一个插件接口类,作为主程序与插件之间通信的桥梁,定义普通成员函数(纯虚函数)、槽函数(纯虚函数)、信号(不能为虚)。在接口类中使用 Q_DECLARE_INTERFACE() 通知 Qt 元对象系统这里有这么个接口。这个接口需要继承QObject;
- 继承接口类,实现其中的虚函数。并:a) 使用 Q_PLUGIN_METADATA()宏导出插件;b) 使用Q_INTERFACES()通知元对象系统此插件使用了哪些接口类;
- 在主程序中利用QPluginLoader加载插件,使用QPluginLoader::instance()方法实例化插件,使用qobject_cast强制转换为接口类指针,connect有关信号和槽;
- 开始愉快的使用;
注意:主程序、接口、插件应分别作为3个子工程。主程序和插件需要调用接口生成的lib文件,否则会出现未定义的外部符号错误。https://stackoverflow.com/questions/50516359/declaring-signals-in-interface-class-using-qt-plugin-system-with-new-signal-slot
二、实现
2.1 工程(Qt creator)
2.1.1 新建项目
新建一个子项目目录,这个项目将包含主工程、接口和插件三