实战详细讲解Qt插件plugin的编写与用法
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
1.Qt的插件是什么优点是什么
所谓的插件只不过是重载了虚函数的dll这跟抽象工厂类类似这便是插件的原理。qt的插件可以说是一种动态库
在函数中我们导入Interface接口文件也就是插件接口文件不需要依赖静态库生成代码类似C/C++关键字extern。而在最后我们通过系统的API加载dll或者so这个可以自行百度查阅 “动态库加载的两种方式”。
这样做的好处定义开发范式面向Interface编程内部封装模块和整体流程开发分离提高开发效率。应用场景QtCreator-IDE、WPS、visual studio、Nodepad++等等都是采用这种开发方式。
2.实战项目需求
有一个嵌入式的显示屏需要编写软件来写入数据。显示屏的规约已经有一个文档了现在需要阅读文档然后根据显示屏规约封装按页刷显示屏整体数据接口、封装单独修改指定页名称/型号/数量接口使用插件方式封装。 封装规约文档部分截图如下
显示屏如下
3. 程序设计分析
具体就不讲那么多了我只需要根据显示屏规约将特定的字符转化为16进制等方式通过串口通信发送给显示屏从而实现控制显示屏的显示
我实现的软件如下
点击写入后将指定数据写入到显示屏中
软件的界面我写好了现在需要写一个插件将接口都封装好给我的软件调用然后将接口返回的值通过串口通信写入显示屏中
接下来讲解插件的编写
4.Qt插件的编写
创建完成后看到如下界面
Qt模板中默认继承了QGenericPlugin的类这里我们不需要用到选择自己写一下抽象类来继承然后子类来实现。
我们新建一个头文件抽象类是不需要实现的所以新建一个头文件即可
这里我新建了一个PackDataApi的头文件然后根据需求加入文档的接口有四个接口这些接口是给我的软件调用的。比如说我要修改显示屏的用户名和密码调用后只需要输入要修改的用户名和密码接口就会返回特定的字符串给你你只要在把这些字符串发送显示屏就可以修改显示屏的用户名和密码了。
还有类外的这两行是干嘛的呢
#define PackDataApi_iid "PackDataPlugin.packdataapi"
Q_DECLARE_INTERFACE(PackDataApi, PackDataApi_iid)
Q_DECLARE_INTERFACE类名标识符
此宏用于把标识符与类名接口关联起来。这个标识符是唯一的这个宏通常在被放到一个类被定后的位置。
这个是Qt实现插件必须要有的一个宏 把标识符与类名接口关联起来。标识符PackDataApi_iid我一般用"工程名.接口类名"来标识看个人习惯啦不重复就行
抽象类接口都写好后回到要实现的子类中把默认继承的类改为自己实现的抽象类前面在继承一个QObjecet如下图所示
发现还用到了两个宏
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID PackDataApi_iid FILE "PackDataPlugin.json")
#endif // QT_VERSION >= 0x050000
Q_INTERFACES(PackDataApi)
第一个Q_PLUGIN_METADATA
这个宏被用于声明元数据这个元数据是被实例化插件的一部分。
这个宏需要通过对象声明被实例化接口的IID并且要引用包含元数据内容的文件。
在Qt插件源码里面应该宏应该只能出现异常。
注意这个宏只能出现在可以被实例化的类中不能放在抽象类中。
FILE是可选参数他指向一个json文件。
这个json文件要包含在构建目录中为资源文件创建插件模板时已经自动生成并且已经包含在里面了不然moc会出错。
Q_INTERFACES
此宏告诉Qt哪些接口被类实例了。这个宏通常用于插件的实例
这几个宏是必须要写的Qt规定好的
然后实现接口即可加入自定义的函数辅助完成接口的开发如下所示
具体实现我就不展示了主要是理解插件开发的过程
实现后然后编译会发现在生成目录下有一个动态库生成这个就是我们要给程序动态加载调用的库加载后转化为接口类调用即可
5.插件的调用
我们编译好插件程序生成动态库了接下来怎么调用呢
调用时只需要动态库和实现接口的头文件即可拿我的软件程序举例将生成的动态库复制到程序目录下或者指定目录下。
在把接口头文件加入到程序工程目录当中然后如下所示
然后在要加载动态库的文件中包含接口头文件
然后加载插件
加载插件代码如下通用的注意下加载插件的目录即可
void GlobalHelper::loadPlugins()
{
QDir pluginsDir(QCoreApplication::applicationDirPath());
qDebug()<< (QString("正在加载BasePageApi插件路径[%1]").arg(pluginsDir.path()));
for(QString fileName: pluginsDir.entryList(QDir::Files)) {
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
if (plugin) {
m_dataApi = qobject_cast<PackDataApi *>(plugin);
if (m_dataApi) {
qDebug()<<"BasePageApi插件加载成功";
return;
}
}
}
if(QMessageBox::critical(nullptr, "警告", "BasePageApi插件加载失败", QMessageBox::Ok)==QMessageBox::Ok) {
qDebug()<<("BasePageApi插件加载失败");
}
}
这样子就完成调用啦
简单叙述调用过程1.添加接口头文件 2.加载动态库 3.调用
如果要给别人调用的话我们只需要写好接口文档怎么调用即可接口是干嘛的参数是什么意思等等。
总结感言
qt插件的开发可以说是动态库的开发因为调用方式类似多熟悉一下利用Qt框架开发很简单的。
在想想这种调用过程有的熟悉比如公司买了一堆摄像头公司要对摄像头进行二次开发实现自己想要的功能集成到一套设备里去然后在卖给用户。
此时厂商肯定会提供开发文档并给你SDK包软件开发工具包 包里你会发现只有头文件和一堆库文件没有源文件因为实现的过程是产商公司保密的给你看还得了。所以都封装成了库的形式给你调用如静态库或者动态库。这也是为什么会有库这种东西产生为了自己写的东西不给别人知道我怎么写的。封装起来保密这可是自己的知识产权呀
还有Qt插件的开发或者说库的开发是独立的一个模块。一般来说一个大工程是有很多模块组成的每个模块开发的人不一样每个模块不同的人各司其职模块都开发完后在整合到起立调用优化最终完成一个工程。这样子的优点是开发效率高各司其职使软件开发更加独立程序模块直接独立.......
就讲解那么多啦写了几个小时啦肝不下啦觉得对你有帮助的点个赞再走⑧