1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| QuikPaltformTest |--> bin // 打包后可执行程序 |--> doc // 文档 |--> trunk |--> bin // 平台的动态库 |--> include // 平台的头文件 |--> CoreApp |--> CoreLib |--> CoreUi |--> KIQtGui |--> MyUI |--> server |--> server_imp |--> ToolsLib |--> lib // 平台的静态库 |--> src // 自定义源码 |--> plugins // 自定义插件 |--> MyUI |--> PluginGreetServer |--> PluginUIA |--> PluginUIB |--> PluginUIC |--> QuikPlatformIDE // 工程目录 |--> QuikPlatformIDE.sln // vs启动文件 |--> ...
|
创建插件
QuikPaltform平台封装了一套插件机制,通过开发各种功能插件组装起来形成一个软件。软件是分层结构,底层是quikpaltform平台,实现一些公共操作和框架代码,其上则是各种功能插件。插件分为UI插件、Server插件,他们遵循的规范都大同小异,分为声明接口、实现接口、注册这3个步骤。下面以Demo中”SayHello”服务接口为例:
1.声明对外提供的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ... namespace Kcc { namespace Greet { class IGreetServer { public: virtual void SayHello() = 0; virtual ~IGreetServer() {} }; typedef QSharedPointer<IGreetServer> PIGreetServer;
enum { Notify_SayHello = 1 }; }} ...
|
2.实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ...
class GreetServer : public ServerBase, public IGreetServer { public: GreetServer(); ~GreetServer();
public: virtual QString GetServerGroupName() const { return SERVER_GROUP_IGREETSERVER_NAME; } virtual QString GetInterfaceDefName() const { return SERVER_INTERFACE_IGREETSERVER_NAME; } virtual unsigned int GetVersion() const { return SERVER_VERSION; }
public: virtual void SayHello(); }; ...
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ... void GreetServer::SayHello() { LOGOUT(QString("GreetServer SayHello"), LOG_NORMAL);
PIServerInterfaceBase pserver = RequestServer(SERVER_GROUP_IGREETSERVER_NAME, SERVER_INTERFACE_IGREETSERVER_NAME);
NotifyStruct notifyStruct; notifyStruct.code = Notify_SayHello; notifyStruct.paramMap["Sender"] = "come from Greetserver";
if (pserver) { pserver->emitNotify(notifyStruct); } } ...
|
3.插件注册
1 2 3 4 5 6 7 8 9 10 11 12
| ...
class PluginGreetServer : public Module { DEFINE_MODULE public: PluginGreetServer(QString strName); ~PluginGreetServer(); }; ...
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ...
REG_MODULE_BEGIN(PluginGreetServer, "", "PluginGreetServer") REG_MODULE_END(PluginGreetServer)
PluginGreetServer::PluginGreetServer(QString strName):Module(Module_Type_Normal, strName) {
RegServer<GreetServer>(new GreetServer()); } ...
|
使用插件
1. 通过直接获取插件对象指针来调用其接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ... class PluginUIB :public QWidget, public Module { Q_OBJECT DEFINE_MODULE public: PluginUIB(QString strName); ~PluginUIB();
public: virtual void init(KeyValueMap ¶ms); virtual void unInit(KeyValueMap &saveParams);
private: PIGreetServer m_pGreetServer; }; ...
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| ... void PluginUIB::init(KeyValueMap ¶ms) { m_pGreetServer = RequestServer<IGreetServer>(SERVER_GROUP_IGREETSERVER_NAME, SERVER_INTERFACE_IGREETSERVER_NAME); if (!m_pGreetServer) { LOGOUT("IGreetServer未注册", LOG_ERROR); } }
void PluginUIB::unInit(KeyValueMap &saveParams) { m_pGreetServer.clear(); }
void PluginUIB::onPluginBTest() { ui.textEdit->append("面板B的按钮已经被按下"); if (m_pGreetServer) { m_pGreetServer->SayHello(); } }
|
2. 通过消息发布/订阅的形式使用插件接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
void PluginUIC::init(KeyValueMap ¶ms) { PIServerInterfaceBase pGreetserver = RequestServer(SERVER_GROUP_IGREETSERVER_NAME, SERVER_INTERFACE_IGREETSERVER_NAME); pGreetserver->connectNotify(Notify_SayHello, this, SLOT(onRecieveGreetMsg(unsigned int, const NotifyStruct&))); }
void PluginUIC::onRecieveGreetMsg(unsigned int code, const NotifyStruct& param) { if (code == Notify_SayHello) { QString strGreetMsg = param.paramMap["Sender"].toString(); ui.textEdit->append(strGreetMsg); } QMessageBox::about(this, tr("测试双击菜单"), tr("双击响应!")); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
void GreetServer::SayHello() { LOGOUT(QString("GreetServer SayHello"), LOG_NORMAL); PIServerInterfaceBase pserver = RequestServer(SERVER_GROUP_IGREETSERVER_NAME, SERVER_INTERFACE_IGREETSERVER_NAME);
NotifyStruct notifyStruct; notifyStruct.code = Notify_SayHello; notifyStruct.paramMap["Sender"] = "come from Greetserver"; if (pserver) { pserver->emitNotify(notifyStruct); } }
|
补充(2023/6/20)
最新平台框架对插件的使用有些更新,更加简化了。但是大体原理还是一样,这里稍微描述下原理流程:
- 首先软件分为两层,平台层和插件层。平台层实现公共操作和框架,独立打包,安装到环境变量中,插件层在平台之上,实现具体功能模块。
- 插件内部对象采用纯虚函数定义对外功能接口,内部实现,即插件的功能逻辑。
- 插件外部对象用
__declspec(dllexport)导出dll,是对外的唯一入口,由平台加载,检测。外部对象构造时会new内部对象,然后记录下来。
- 对于平台加载过程: 平台 –> 加载dll,构造插件外部对象并初始化 –> 构造插件内部对象并初始化。
- 对于使用者流程是: 向平台请求获取插件内部对象的指针,然后就可以访问内部对象实现的接口了。