【 协 议 】: 本软件受软著保护,遵守GPL3.0开源协议,您可以自由复制,传播,修改它的副本,但必须保留作者版权信息并遵守GPL3.0协议,上传并公开相关源码,否则视为违规。
【 说 明 】: 项目旨在为个人提供学习指引及开发思路,试图规范和助力国产化工控软件发展。项目在实际中不断维护和升级,但只上传了全套社区版源码(HostView:v2.0.0.1,QCPF_Model: v2.0.0.4 ,QCPF_ViewModel:v1.0.0.6),您可以贡献您的源码来推动项目更新和bug修复。另外,商用可以选择企业版源码(HostView:v4.1.0.3,QCPF_Model: v3.1.0.2 ,QCPF_ViewModel:v2.5.0.4)。本文主要阐述"社区版"的主要特性,"企业版"请点击下方链接。
【 社区版 】: QCPFrame In Github QCPFrame In Gitee QCPFrame in CSDN
【 企业版 】: 企业版介绍及更新日志 企业版演示程序 示例工程 应用案例
图1. 企业版效果图
一直以来,笔者都在从事工控相关的行业,至今已有15年的职业历程。为了更好的将自己的经验应用于实践,同时汲取各方力量助力这一开放式的框架,遂将其进行免费开源。
框架最初应用于航空自动测试系统,即MV结构,View即一个用于控制测试启动,停止,存储,报表生成等基本操作的UI界面,而M是测试序列Tps的集合,他无关界面,只是调用底层硬件驱动,描述测试流程。
后来笔者又进入航天测控及军工领域,这一行业的特点就是需求不确定,需要经常添加或修改UI及功能,项目周期短更迭快,需要一个可裁剪,可重用,松耦合,可同步开发的高效框架。
说到这里,笔者除了是一个架构师以外,也是一个原创音乐爱好者。虽然音乐上并无建树,但在进行编曲的时候,国外音频宿主软件倒是给了笔者很大的设计启发。音频宿主软件是一个容器。用户在使用的过程中,可以安装各种各样的音色和效果器插件。宿主根本不关心用户会加载多少插件以及插件功能,它只是负责管理好他们,提供各种供用户操作的插件接口。因此,我理解一个好的框架就像一个舞台,只是用于承载乐器插件完成一场美妙得音乐会。
QCPFrame 全称Qt-based Commonly-used Plugin Framework。它是一个开源的基于Qt的跨平台插件开发框架,旨在提高基于PC及Linux平台下工控软件设计的通用性,重用性,高效性,可裁剪性,松耦合性。在QCPFrame中,您可以基于控制台或者服务来运行最小插件系统,也可以通过view editor(也是一个插件)来编辑带有UI的桌面程序。在QCPFrame中,一切皆插件,甚至一个后台功能,菜单项,工具栏项,状态栏项,dock片都可以是一个插件。插件在编辑和配置插件,包括它自己,这一切就像是在搭积木,使得模块开发人员只用专注于本模块的开发,而无需过多关注软件系统最终的集成。
QCPFrame的设计思路是将需求后置,即用插件的形式不断填充既有功能,通过接口提供各种通讯机制来帮助他们之间协同工作。
作为基础版的QCPFrame,它具备以下特性:
实现了动态扫描插件并加载的功能,这便于在线更新等相关功能的开发。
由于框架采用了Model-ViewModel的架构,一切皆插件的设计思路,那么可执行程序对于系统而言,不过是一个启动器而已,大部分功能是需要插件来实现,比如插件管理器,视图编辑器,系统设置等等,这些从前是放在主程序中的功能模块,如今也是作为一个插件被宿主统一管理。如此以来,系统的升级将意味着只需要升级插件,因为主程序基本没有什么代码。这些用于不断扩充系统功能的组件,在系统中被称之为系统组件。
非系统组件用于实现二次开发时,对于业务的实现。这样把框架本身和业务分开的方式,不但提高了系统的灵活性,也可以将框架与业务解耦。
在项目开发的过程中,我们经常会遇到有些UI需求,是多组相同的界面及功能,只是他们对应的硬件通道不同而已。相信很多人的做法就是复制代码,或者写一个类new出多个对象。有了组件克隆,你只需要做一个通道,其他的可以轻松通过组件管理器来克隆出一模一样的组件,他们是深拷贝实现的,因此不必考虑指针的关联性。出于安全考虑,只有用于实现业务层的组件支持克隆,而系统组件的克隆不被允许。
组件排序功能,使开发者能够调整组件在运行时被加载的顺序,这在某些与硬件初始化相关的应用中至关重要。系统提供了"Model构造时","Model析构时",“View构造时”,“View第一次显示时”,“View关闭时”这几个节点的信号,系统运行至这几个节点时,会按照组件排序的顺序,依次调用组件的这些接口函数。
框架的接口提供了丰富的共享内存类型,供插件之间同步时使用,这包含C++基本类型,链表,队列等等。
跨平台是Qt先天的优势,在国产化进程日益高涨的未来,对于国防工控软件来说,更是提出了更高的要求。本框架分别在Windows 7专业版,Ubuntu 18.4,银河麒麟V10操作系统上进行了部署测试,达到了良好的效果。
前面提到QCPFrame具有通用性,重用性,高效性,可裁剪性,松耦合的特性,那么它在实际开发中,能带来什么好处,让我们来分析一下。
它支持带有UI的应用程序,同时也支持无UI的控制台应用程序。框架本身与业务无关,我们可以将它应用于任何业务方向,换言之,所有二次开发的业务都取决于插件。
它的优势并非“界面可编辑”,对于内核而言,用于组织UI的ViewModel及插件ViewEditor也是可有可无的存在,他们只是作者用于设计UI的一种思路,当你需要一套不同的View样式和思路时,由于内核是独立不变的,那你只需要重新设计View层,而处于业务层的plugin甚至都不用动。
当所有业务都以插件的形式存在时,一些常用的功能可以被写成插件,在不同项目中重复利用将可以大大提高开发效率。它可以是一个无界面的IVI仪器驱动模块,Matlab算法模块,OpenCV图像处理模块,CRC校验模块或者是带UI的串口助手模块,日志管理器模块,文件/目录浏览器模块等等。
合理的松耦合业务层设计,可以将大的功能模块分割为小的插件模块,小组“并行开发”将大大提高开发的效率,显著缩短开发周期。
另外,如果后期需要对某一个业务单元进行维护升级,并不需要把所有代码拿出来,只需要在特定插件模块中进行。一旦项目所属的开发人员发生更替,对新的开发者而言,缩小了维护范围,使维护工作变得更轻松和安全。
与传统软件框架相比,QCPFrame天生可裁剪,这首先体现在“插件管理器”和“系统管理器”这两个系统级插件上。我们可以轻松在线决定将哪些插件使能,哪些插件被禁用。
另外,QCPFrame原生提供了UI的可编辑功能,通过ViewEditor编辑好的带权限的UI配置,当不同的用户登录进来,UI元素将根据权限决定是否对用户使能。比如游客登入将不能进行任何形式的管理,管理员用户登入只能进行系统管理,用户管理,而超级管理员不仅可以进行前面的管理,还能编辑UI等等。
耦合性大多体现在模块与模块之间,层与层之间的交互上,QCPF_Model提供了不止一种途径用于模块间的松耦合通讯,这在作者【开源】基于Qt的跨平台插件开发框架QCPFrame(二)一节中有讲。
实践证明,松耦合性不仅有利于项目并行开发时的高效性,也有利于后期维护。维护人员在特定模块里的代码改动,将对其他模块构成最小影响,甚至毫无影响。
公司知识产权,项目中客户的保密要求,对于一个企业的重要性不言而喻,然而核心技术防得了外人,却防不了内部员工的流动,风险巨大。采用插件式框架,可以有效避免核心模块的公开,特别是二次开发时,只要核心插件或模块不变,就无需提供源码,开发人员便只专注于其他非核心插件的开发或维护,从而能有效防范核心模块或具有保密性要求的模块扩散。
图3. QCPFrame 系统结构图
从以上的系统结构图来看,大的模块分为Model,ViewModel及View。
Model为系统模型,分为QCPFModel和PluginModel,其中QCPFModel的实例即为内核Core,他按照配置文件对插件进行初始化,安装及管理,在插件与内核之间,插件与插件之间建立通讯桥梁,提供内核接口等。安装包括系统功能设置,插件使能/禁用,插件克隆,运行时排序等功能。Model不编辑配置文件,配置文件的编辑工作将由System Manager插件完成。
PluginModel则是所有Plugin的基类模型,它分为系统插件和非系统插件,他们的特征和设计方向是贴近系统,并且将来会越来越更加固化,用以扩充系统功能,比如系统管理器,插件管理器,用户管理器等插件。非系统插件则主要用于实现特定业务模块,以框架的应用方向为测试测控来讲,板卡驱动封装,算法,以及测试模块等,都可以设计成非系统插件。
ViewModel用于定义视图模型,它能够根据配置文件在View中绘制菜单,工具栏,状态栏及工作区内容,跟Model类似,ViewModel也不编辑配置文件,而UI编辑工作,是由一个叫做View Editor的插件来完成。ViewModel与Model可以没有任何关联,它只是引入了一种典型的视图模板,并帮你从配置文件动态绘制他们。当你不喜欢这个View模板时,也可以重写或者修改ViewModel来快速构建你喜欢的模板样式。
View是一个可执行程序,用于承载内核模型和视图模型,因为所有的工作都被Model和ViewModel完成了,所以主程序代码量相当少。对于一个控制台程序Console来讲,ViewModel不参与运行。Core+Console即为最小插件系统,它具备基本的插件管理和通讯能力,可以当作一个控制台或者服务程序来使用。
为了直观的介绍QCPFrame,我们通过系统中一个有趣的插件View Editor来介绍QCPFrame的便捷之处。如上图2所示,View界面主要由菜单栏,工具栏,dock窗口,状态栏组成。而view editor插件要做的工作,就是提供一个UI编辑器,并通过访问Model与组件特定的功能进行绑定,这一切都是可视化的,你可以随心调整UI部件的位置和展示方式。
菜单工具栏与用户权限挂钩,可以实现不同的用户进入后是否菜单工具栏对其可用。
图4. View Editor 菜单编辑功能
对于菜单栏来说,其实可以认为每个顶级菜单项即为一颗树。View Editor在设计时,允许用户随意添加树节点,除了顶级菜单项以外,可以任意添加分隔符,并通过方向键调整层级关系。每个菜单项可以设置查看权限,这有助于不同权限的用户登陆后看到不同的权限的UI。添加好树节点以后,就可以通过Load Action按钮给该菜单项挂载一个Action,从Action Viewer页面来找到你要的Action。
图5. Action Viewer工具
一旦完成Action挂载,该菜单项再下一次启动后,便可以通过信号槽与组件指定的功能挂接起来。通过Load Icon按钮为该菜单项设定一个图标,该图标将一直伴随这个Action。需要说明的是这些可以挂载的Action是预先在插件工程中开发好的,随着插件模块的积累,对于View Editor来说,可选可编辑的Action也将更丰富。
图6. View Editor 工具栏及状态栏编辑功能
对于工具栏来讲,View Editor允许用户添加多个工具栏,并为指定工具栏添加Action, Action下拉框的项来自菜单编辑页面所映射过的Action,也就是说你只能先在菜单下加入该新Action,才能在工具栏里添加它。多工具栏的支持,可以让你实现类似Word一样的复杂视图,值得一提的是,工具栏编辑模块还允许你将插件里开发好的任意widget展示到工具栏里,如图1中工具栏右侧的搜索框就是自定义控件,Widget Viewer是一个插件widget列表查看器,你可以通过它找到你要的widget。
图7. Widget Viewer工具
系统只提供了一个状态栏,其编辑类似于工具栏,只不过没有分割符,因为Qt的状态栏会自动为每个item添加分隔符。
对于workspace,是以dockwidget为容器的工作区,通过widget选择功能,你可以从已经开发好的widget列表中选择你要的,在重新启动以后,系统会将这些widget放入dockwidget容器中,系统做了Layout存储,因此当你通过拖拽,调整好需要的UI并关闭系统时,该Layout将会被保存,包括工具栏的位置及Dock,如图1所示。
其实说到这里,本节内容不过是在讲一个插件,它只是整个系统中一个小的模块,我的意思是说,至此我们可以把任何功能与主程序剥离,而使其成为一个易于升级的热插拔模块,所有的重心都在插件上,view或console只是一个启动器罢了。
图9. ubuntu 下运行最小插件系统
图10. ubuntu 下运行带UI的QCPFrame插件系统--登录界面
图11. ubuntu 下运行带UI的QCPFrame插件系统--主界面
图12. ubuntu 下运行带UI的QCPFrame插件系统--View Editor
本篇文章简单介绍了一下该开源项目的主旨,系统结构,设计理念及系统中的一些概念,说的不对的望各位大神指点。下一篇,我会介绍框架的二次开发及接口,也会展望一下未来,制定下一步的设计目标,谢谢。
【开源】基于Qt的跨平台插件式开发框架QCPFrame(二)