手机网站 制作教程,网站新闻发布系统模板,做网站需要什么技术人员,喜迎二十大演讲稿文章目录 一、项目示例1.导航栏操作页面操作示例图2.打开所有页面操作示例图3.打开指定界面操作示例图3.插件重载操作演示 二、插件逻辑个人理解1.QPluginLoader的简单使用2.子插件的基本要素 三、项目结构#xff08;思路#xff09;简述1.定义插件接口类2.定义插件类别一个… 文章目录 一、项目示例1.导航栏操作页面操作示例图2.打开所有页面操作示例图3.打开指定界面操作示例图3.插件重载操作演示 二、插件逻辑个人理解1.QPluginLoader的简单使用2.子插件的基本要素 三、项目结构思路简述1.定义插件接口类2.定义插件类别一个主项目若干子插件 3.主项目及子插件的关联 四、源码此处列举主项目和一个子插件源码为例1.主项目相关文件iplugindatabusinterface.hcommondefinsmainwindowmain.cpp 2.子插件页面1相关文件pagefirstplugin 总结 一、项目示例
1.导航栏操作页面操作示例图
下图演示了通过导航栏打开和关闭页面并在主页插件显示的操作。
2.打开所有页面操作示例图
下图演示了一键打开所有界面并同事更新导航来页面状态的操作。 3.打开指定界面操作示例图
下图演示了根据不同项按钮打开指定界面的操作并且同时更新对应导航栏状态。
3.插件重载操作演示
下图演示了指定页面重载指定页面的逻辑演示。 注本文代码此处重载并非同一插件的重载而是将当前使用插件卸载然后通过更新插件路径从而加载一个全新的插件逻辑。
二、插件逻辑个人理解
1.QPluginLoader的简单使用
使用步骤如下
**设置库文件**创建一个QPluginLoader对象可通过构造传参或setFileName函数设置库文件**加载库文件**使用QPluginLoader对象的load函数加载库文件**获取插件指针**通过QPluginLoader对象的instance函数获取一个QObject指针然后通过转换获取再使用插件指针获取控件对象等操作卸载插件. 通过QPluginLoader对象的unload函数卸载插件该函数会自动释放插件指针对象。
2.子插件的基本要素
继承自定义接口并根据功能实现对应的接口函数。使用Q_DECLARE_INTERFACE将接口对象声明给元对象保证可使用Q_INTERFACES添加该接口。使用Q_INTERFACES添加后可使用qobject_cast转换为定义接口类不添加该标识符使用dynamic_cast强制转换也可使用但不推荐。使用Q_PLUGIN_METADATA添加后可使得QPluginLoader的instance函数获取到接口类指针。
三、项目结构思路简述
1.定义插件接口类
插件与插件之间无法直接通信此时就需要一个接口作为中间类建立通信的桥梁提供保障插件正常工作的函数如收、发数据的函数并且要求进行通信的子插件都需要继承接口类并实现对应的通信函数以及在该类文件中定义唯一标识符使得Qt能通过标识符识别该接口类。
插件唯一标识符
// 通过宏定义插件标识符
#define InterfaceIdent plugin.plugindatabusinterface插件相关必要函数
signals:// 数据通信信号void sigPluginCommTriggered(const StCommData data);
public:// 数据接收处理函数virtual void recvPluginCommData(const StCommData data) 0;// 初始化函数virtual void initialize() 0;// 初始化状态函数virtual bool isInitialized() const 0;// 获取插件名称virtual QString name() const 0;// 创建插件对象virtual QWidget *createWidget() 0;
public slots:// 所有插件初始化完成函数virtual void slotInitialized() 0;2.定义插件类别
一个主项目
管理子插件集合以及负责各个子插件的互相通信数据转发主项目负责加载、管理、卸载子插件并处理各个插件间的消息转发并且主项目包含main.cpp使得程序从该入口运行。
主项目的目录结构
若干子插件
某一功能的集合负责该功能的消息发送及消息处理要求继承接口类并个性化实现接口类虚函数且子插件中的插件类中需添加指定的插件宏。
子插件接口宏使用 // 添加后可使用qobject_cast转换为定义接口类不添加该标识符使用dynamic_cast强制转换也可使用但不推荐Q_INTERFACES(IPluginDataBusInterface)
#if QT_VERSION 0x050000// 添加后可使得QPluginLoader的instance函数获取到接口类指针Q_PLUGIN_METADATA(IID InterfaceIdent)
#endif // QT_VERSION 0x050000子插件目录结构 其他子插件 除开初始化显示的导航栏插件和主页插件固定外子页插件是通过导航栏插件解析配置文件获取因此导航栏插件目录下添加其他插件信息配置文件。 如下图
3.主项目及子插件的关联
以本文项目举例详情请看源码 在主项目头文件中添加插件信息容器集合处理。 插件初始化时将对应插件存储至相关容器并关联数据信号处理消息。
四、源码此处列举主项目和一个子插件源码为例
1.主项目相关文件
iplugindatabusinterface.h
#ifndef IPLUGINDATABUSINTERFACE_H
#define IPLUGINDATABUSINTERFACE_H#include QObject
#include commondefins.h// 通过宏定义插件标识符
#define InterfaceIdent plugin.plugindatabusinterfaceclass IPluginDataBusInterface : public QObject
{Q_OBJECT
public:IPluginDataBusInterface(QObject *parent Q_NULLPTR):QObject(parent){}signals:/*** brief sigPluginCommTriggered 插件通信信号触发* param data 插件数据*/void sigPluginCommTriggered(const StCommData data);public:/*** brief recvPluginCommData 接收插件数据信息* param data 插件数据*/virtual void recvPluginCommData(const StCommData data) 0;/*** brief initialize 初始化函数*/virtual void initialize() 0;/*** brief isInitialized 是否初始化* return 初始化状态*/virtual bool isInitialized() const 0;/*** brief name 获取插件名* return 插件名*/virtual QString name() const 0;/*** brief createWidget 创建插件控件* param parent 插件控件父对象* return 插件控件指针*/virtual QWidget *createWidget() 0;public slots:/*** brief slotInitialized 初始化完成槽函数*/virtual void slotInitialized() 0;protected:bool m_initialized; // 是否初始化变量
};// 将接口对象声明给元对象
Q_DECLARE_INTERFACE(IPluginDataBusInterface, InterfaceIdent)#endif // IPLUGINDATABUSINTERFACE_H
commondefins
commondefins.h
#ifndef COMMONDEFINS_H
#define COMMONDEFINS_H#include QHash
#include QPair
#include QString
#include QJsonObject
#include QMessageBox#define DefaultPluginLoadPath QString(./) // 默认插件路径enum EmDataCode{PAGE_COMM 0,PAGE_OPEN,PAGE_CLOSE,PAGE_RELOAD,PAGE_RELOAD_FAILED,PAGE_OPEN_ALL,PAGE_INIT,PAGE_INIT_FAILED,
};typedef struct StCommData {EmDataCode code; // 数据码QString pageName; // 页面名称QJsonObject commData; // 通信数据StCommData(){}StCommData(EmDataCode code, QString pageName, QJsonObject commData) {this-code code;this-pageName pageName;this-commData commData;}
}StCommData;// 初始化加载插件信息
typedef struct StInitPluginLoaderInfo {// 当运行模式为Debug时使用的区分使用
#ifdef QT_DEBUGconst QString navigationBar DefaultPluginLoadPath navigationbarplugind.dll;const QString homePage DefaultPluginLoadPath homepageplugind.dll;
#elseconst QString navigationBar DefaultPluginLoadPath navigationbarplugin.dll;const QString homePage DefaultPluginLoadPath homepageplugin.dll;
#endif
// const QString homePage DefaultPluginLoadPath pagefirstplugin.dll;
}StInitPluginLoaderInfo;// 主页加载插件信息
typedef struct StPluginCommInfo {const QStringList listNavigationBarInfo {PageFirst, PageSecond}; // 导航栏列表信息}StHomePagePluginLoaderInfo;#endif // COMMONDEFINS_H
commondefins.cpp
#include commondefins.h// 创建变量保证项目可以全局使用
StInitPluginLoaderInfo g_stInitPluginLoaderInfo;mainwindow
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include QMainWindow
#include QPluginLoader
#include iplugindatabusinterface.hnamespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent Q_NULLPTR);~MainWindow();/*** brief initial 初始化函数*/void initial();signals:/*** brief sigInitialized 初始化完成信号*/void sigInitialized();private slots:/*** brief slotPluginCommTriggered 插件通信槽函数* param data 通信数据*/void slotPluginCommTriggered(const StCommData data);private:Ui::MainWindow *ui;QPairQPluginLoader *, IPluginDataBusInterface * m_pairNavigateInfo; // 导航栏指针信息QPairQPluginLoader *, IPluginDataBusInterface * m_pairHomePageInfo; // 主页指针信息QHashQString, QPairQPluginLoader *, IPluginDataBusInterface * m_hashPageLoaderIPlugin; // 子页指针信息};#endif // MAINWINDOW_H
mainwindow.cpp
#include mainwindow.h
#include ui_mainwindow.h#include commondefins.h
#include QDebug
#include QDateTime
#include QFileextern StInitPluginLoaderInfo g_stInitPluginLoaderInfo;MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui-setupUi(this);initial();
}MainWindow::~MainWindow()
{// 卸载所有库m_pairNavigateInfo.first-unload();m_pairHomePageInfo.first-unload();foreach(auto info,m_hashPageLoaderIPlugin) {info.first-unload();}delete ui;
}void MainWindow::initial()
{// 初始化导航栏插件m_pairNavigateInfo.first new QPluginLoader(g_stInitPluginLoaderInfo.navigationBar, this);m_pairNavigateInfo.second qobject_castIPluginDataBusInterface *(m_pairNavigateInfo.first-instance());connect(m_pairNavigateInfo.second, IPluginDataBusInterface::sigPluginCommTriggered, this, MainWindow::slotPluginCommTriggered);connect(this, MainWindow::sigInitialized, m_pairNavigateInfo.second, IPluginDataBusInterface::slotInitialized);ui-layoutNavigation-addWidget(m_pairNavigateInfo.second-createWidget());// 初始化主页插件m_pairHomePageInfo.first new QPluginLoader(g_stInitPluginLoaderInfo.homePage, this);m_pairHomePageInfo.second qobject_castIPluginDataBusInterface *(m_pairHomePageInfo.first-instance());connect(m_pairHomePageInfo.second, IPluginDataBusInterface::sigPluginCommTriggered, this, MainWindow::slotPluginCommTriggered);connect(this, MainWindow::sigInitialized, m_pairHomePageInfo.second, IPluginDataBusInterface::slotInitialized);ui-tabWidget-addTab(m_pairHomePageInfo.second-createWidget(), u8主页);emit sigInitialized();
}void MainWindow::slotPluginCommTriggered(const StCommData data)
{switch (data.code) {case PAGE_INIT: {// 不同运行模式使用的库名不一样
#ifdef QT_DEBUGQString pluginName data.commData.value(pluginName).toString() d.dll;
#elseQString pluginName data.commData.value(pluginName).toString() .dll;
#endif// 指定加载库路径QPluginLoader *pageLoader new QPluginLoader(DefaultPluginLoadPath pluginName, this);// 链接页面信号IPluginDataBusInterface *pageInteface qobject_castIPluginDataBusInterface *(pageLoader-instance());// 直接判断接口对象加载失败时指针为0x00相当于falseif(pageInteface) {// 判断页面是否存在if(m_hashPageLoaderIPlugin.contains(data.pageName)) {QMessageBox::information(this, u8提示, data.pageName u8页面名称已存在);break;}connect(pageInteface, IPluginDataBusInterface::sigPluginCommTriggered, this, MainWindow::slotPluginCommTriggered);// 添加页面指针信息m_hashPageLoaderIPlugin[data.pageName] QPairQPluginLoader *, IPluginDataBusInterface *(pageLoader, pageInteface);m_pairHomePageInfo.second-recvPluginCommData(data);}else {StCommData reply data;reply.code PAGE_INIT_FAILED;QMessageBox::information(this, u8提示, data.pageName u8页面信息初始化失败 pageLoader-errorString());m_pairNavigateInfo.second-recvPluginCommData(reply);}break;}case PAGE_OPEN: {// 判断页面是否存在if(!m_hashPageLoaderIPlugin.contains(data.pageName)) {QMessageBox::information(this, u8提示, data.pageName u8页面不存在);}// 判断页面打开状态else if (-1 ! ui-tabWidget-indexOf(m_hashPageLoaderIPlugin[data.pageName].second-createWidget())) {QMessageBox::information(this, u8提示, data.pageName u8页面已打开);}// 获取页面指针并打开页面else {QWidget *page m_hashPageLoaderIPlugin[data.pageName].second-createWidget();ui-tabWidget-addTab(page, data.pageName);ui-tabWidget-setCurrentWidget(page);// 页面打开回执原信息返回m_pairNavigateInfo.second-recvPluginCommData(data);}break;}case PAGE_OPEN_ALL: {// 遍历容器打开所有页面foreach(auto pageInfo, m_hashPageLoaderIPlugin) {ui-tabWidget-addTab(pageInfo.second-createWidget(), m_hashPageLoaderIPlugin.key(pageInfo));}// 页面关闭回执原信息返回m_pairNavigateInfo.second-recvPluginCommData(data);break;}case PAGE_CLOSE: {// 判断页面是否存在if (!m_hashPageLoaderIPlugin.contains(data.pageName)) {QMessageBox::information(this, u8提示, data.pageName u8页面不存在);}// 判断页面打开状态else if (-1 ui-tabWidget-indexOf(m_hashPageLoaderIPlugin[data.pageName].second-createWidget())) {QMessageBox::information(this, u8提示, data.pageName u8页面暂未打开/已关闭);}// 关闭页面else{ui-tabWidget-removeTab(ui-tabWidget-indexOf(m_hashPageLoaderIPlugin[data.pageName].second-createWidget()));// 页面关闭回执原信息返回m_pairNavigateInfo.second-recvPluginCommData(data);}break;}case PAGE_RELOAD: {// 判断页面是否存在if (!m_hashPageLoaderIPlugin.contains(data.pageName)) {QMessageBox::information(this, u8提示, data.pageName u8重载页面不存在);}else if(m_hashPageLoaderIPlugin[data.pageName].first-unload()) {QString fileName m_hashPageLoaderIPlugin[data.pageName].first-fileName().replace(DefaultPluginLoadPath, DefaultPluginLoadPath backup/);// 判断新文件名是否存在存在即更新库名if (QFile::exists(fileName)) {m_hashPageLoaderIPlugin[data.pageName].first-setFileName(fileName);}// 加载库if (m_hashPageLoaderIPlugin[data.pageName].first-load()) {m_hashPageLoaderIPlugin[data.pageName].second qobject_castIPluginDataBusInterface *(m_hashPageLoaderIPlugin[data.pageName].first-instance());m_pairNavigateInfo.second-recvPluginCommData(data);m_hashPageLoaderIPlugin[data.pageName].second-createWidget();}else {StCommData tmpData data;tmpData.code PAGE_RELOAD_FAILED;m_pairNavigateInfo.second-recvPluginCommData(tmpData);QMessageBox::information(this, u8提示, data.pageName u8页面重载失败 m_hashPageLoaderIPlugin[data.pageName].first-errorString());}}else {QMessageBox::information(this, u8提示, data.pageName u8页面重载失败 m_hashPageLoaderIPlugin[data.pageName].first-errorString());}break;}default:break;}
}
main.cpp
#include mainwindow.h
#include QApplicationint main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
2.子插件页面1相关文件
注:该插件控件仅ui添加标识label故仅展示插件文件
pagefirstplugin
pagefirstplugin.h
#ifndef PAGEFIRSTPLUGIN_H
#define PAGEFIRSTPLUGIN_H#include iplugindatabusinterface.h#include QDesignerCustomWidgetInterfaceclass FormPageFirst;
class PageFirstPlugin : public IPluginDataBusInterface
{Q_OBJECTQ_INTERFACES(IPluginDataBusInterface)
#if QT_VERSION 0x050000Q_PLUGIN_METADATA(IID InterfaceIdent)
#endif // QT_VERSION 0x050000public:PageFirstPlugin(QObject *parent Q_NULLPTR);~PageFirstPlugin();// IPluginDataBusInterface interface
public:void initialize();bool isInitialized() const;QString name() const;QWidget *createWidget();void recvPluginCommData(const StCommData data);// IPluginDataBusInterface interface
public slots:void slotInitialized();private:FormPageFirst *m_formPageFirst Q_NULLPTR;
};#endif // PAGEFIRSTPLUGIN_H
pagefirstplugin.cpp
#include formpagefirst.h
#include pagefirstplugin.h#include QtPluginPageFirstPlugin::PageFirstPlugin(QObject *parent): IPluginDataBusInterface(parent)
{m_initialized false;
}PageFirstPlugin::~PageFirstPlugin()
{if(Q_NULLPTR ! m_formPageFirst) {delete m_formPageFirst;m_formPageFirst Q_NULLPTR;}
}void PageFirstPlugin::initialize()
{if (m_initialized)return;// Add extension registrations, etc. herem_initialized true;
}void PageFirstPlugin::slotInitialized()
{}void PageFirstPlugin::recvPluginCommData(const StCommData data)
{}bool PageFirstPlugin::isInitialized() const
{return m_initialized;
}QWidget *PageFirstPlugin::createWidget()
{if(Q_NULLPTR m_formPageFirst) {m_formPageFirst new FormPageFirst();}return m_formPageFirst;
}QString PageFirstPlugin::name() const
{return QLatin1String(PageFirstPlugin);
}#if QT_VERSION 0x050000
Q_EXPORT_PLUGIN2(pagefirstplugin, PageFirstPlugin)
#endif // QT_VERSION 0x050000
总结
本文简易介绍插件使用、部分通信逻辑及插件构建逻辑下一篇出插件创建详细步骤。有需要可私源码 友情提示——哪里看不懂可私哦让我们一起互相进步吧 创作不易请留下一个免费的赞叭 谢谢 ^o^/)
注文章为作者编程过程中所遇到的问题和总结内容仅供参考若有错误欢迎指出。 注如有侵权请联系作者删除