本文由 @lonelyrains 出品,转载请注明出处。
文章链接: http://blog.csdn.net/lonelyrains/article/details/45243671
DevTool模块
1 程序描述
DevManager简称DM,ViewManager简称VM。程序启动后,DevManager内注册对Controller的事件处理回调eventCallbackForDM,以便Dev事件到来时回调;ViewManager内注册对Controller的事件处理回调eventCallbackForVM,以便UI事件到来时回调。eventCallbackForDM内调用dispatchRequestFromCfg解析是否有匹配的事件对应的需求需要处理,如果有而且需要界面,则调用getDataFromDMtoVMForView从DevManager中获取对应界面需要的相应数据,并调用ViewManager的回调requestCallback处理对应的UI请求,最终弹出UI。UI处理完之后,调用eventCallbackForVM,通知Controller对应UI的完成事件,并将UI的返回数据保存在Controller内,然后Controller内调用getDataFromVMtoDMForDev组织数据,调用DevManager的requestCallback请求,最终调用DevApi更新Dev内数据。如果需要提示操作结果,还需要经历一次DM-Controller->VM->Controller的操作。
上述描述是针对Dev事件处理的,也有来源于用户操作的处理。如果是类似修改名称的操作,处理顺序为VM->Controller->DM->Controller->VM-> Controller。
1) VM先启动主页面,响应用户按钮请求,修改名称是在VM内弹框;
2) 填完Dev名称,合法验证通过后,Controller获取数据形成Dev的Request;
3) DM内调用封装好的DevApi实现修改名称,成功之后,返回给Controller;
4) Controller发送UI的Request,说明修改名称成功;
5) VM弹出修改成功提示,用户点击成功;
6) VM通知Controller确认成功。
在5)用户点击成功之前,如果此时用户断开Dev,而且用户需求中要求断开Dev之后关闭相关的对话框,将从DM->Controller->VM完成一次关闭提示框的操作。
在DM和VM之间加一层Controller的好处是所有需要配置定制的部分全部在此部分完成,其他实现可以以库的形式提供。
抽象一层Controller,还有一个好处,是不用在VM内缓存任何数据。比如想实现一个下拉框选择Dev,仅仅有连接/断开事件时传Dev指针到VM内是不够的,需要VM自己维护已有的Dev列表。
UML静态图如下:
2 功能
DevManager、ViewManager 分别实现设备管理、视图管理。主程序内实现控制器的功能,连接各个模块,实现消息的传递、客户定制需求的处理。2.1 设备管理
连接Dev则新建Dev对象存入devMap,所有针对Dev的数据操作都由DevManager进行。除了与Dev通信,还要负责回复Controller的请求数据、调用Controller的回调,通知Controller事件来了。2.2 视图管理
响应Conroller的请求弹出UI,当UI操作结束时,调用Controller的回调返回UI操作的结果。2.3 控制器
Conroller提供回调函数给DevManager、ViewManager,以响应事件,并实现对配置的解析,针对当时的事件,生成相应的请求,提交给DevManager和ViewManager。2.4 性能
2.5 输入项
2.6 输出项
无。2.7 算法
无。2.8 流程逻辑
无。2.9 接口
数据传输统一采用XML格式,如果某些元素是二进制流数据,且不是无符号整型,也先转成十六进制字符串,然后再传输。2.9.1 ViewType定义格式
支持的视图类型:View、ListView、TabView、ImageView、Button、ComboBox、TextView、TableView、TrayView、BubbleView、AnimateView。支持的视图内容布局类型:contentLayout(left/right/center/top/down) marginWidth/marginHeight
支持的布局类型:linearLayout(vertical/horizontal)
支持的宽高类型:height/width(30%/30) %方式定义与父窗口的相对位置,纯数字定义与MFC的rc文件中定义单位相同
例如定义一个竖型的管理工具mainView
<?xml version="1.0" encoding="utf-8"?>
<view>
<viewType>mainView</viewType>
<width>500</width>
<height>400</height>
<IsCenterToDeskTop>true<isCenterToDeskTop>
<linearLayout orientation = "vertical">
<linearName>outline</linearName>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>96%</height>
<!--headline-->
<linearLayout orientation = "horizontal">
<linearName>headline</linearName>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>5%</height>
<backgroundColor>#0001</backgroundColor>
<imageView>
<imageName>logoIco</imageName>
<imageUrl>$(res)/logoIco.png</imageUrl>
<contentLayout>center</contentLayout>
<marginWidth>2%</marginWidth>
<width>5%</width>
<height>96%</height>
</imageView>
<textView>
<marginWidth>2%</marginWidth>
<width>70%</width>
<height>96%</height>
<textValue>$(CustomerName)$(DevName)$(ToolName)</textValue>
</textView>
<button>
<id>btn_min</id>
<action>onMin</action>
<marginWidth>2%</marginWidth>
<width>5%</width>
<height>96%</height>
<imageUrl>$(res)/btn_min.png</imageUrl>
</button>
<button>
<id>btn_max</id>
<action>onMax</action>
<marginWidth>2%</marginWidth>
<width>5%</width>
<height>96%</height>
<imageUrl>$(res)/btn_max.png</imageUrl>
<isEnable>false</isEnable>
</button>
<button>
<id>btn_close</id>
<action>onClose</action>
<marginWidth>2%</marginWidth>
<width>5%</width>
<height>96%</height>
<imageUrl>$(res)/btn_close.png</imageUrl>
</button>
</linearLayout>
<!--logo long-->
<imageView>
<imageName>logoLong</imageName>
<imageUrl>$(res)/logoLong.png</imageUrl>
<contentLayout>center</contentLayout>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>30%</height>
</imageView>
<textView>
<marginWidth>2%</marginWidth>
<width>70%</width>
<height>50%</height>
<textValue>$(CustomerName)$(DevName)$(ToolName)</textValue>
</textView>
<linearLayout orientation = "horizontal">
<linearName>headline</linearName>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>56%</height>
<!--logo-->
<listView>
<id>listView_mainView</id>
</listView>
<!--btnlist-->
<linearLayout orientation = "vertical">
<linearName>btnList</linearName>
<marginWidth>2%</marginWidth>
<width>36%</width>
<height>56%</height>
<button>
<id>btn_change_name</id>
<action>onChangeName</action>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>10%</height>
<isEnable>false</isEnable>
</button>
<button>
<id>btn_view_devinfo</id>
<action>onView devinfo </action>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>10%</height>
<isEnable>false</isEnable>
</button>
<button>
<id>btn_init</id>
<action>onInit</action>
<marginWidth>2%</marginWidth>
<width>96%</width>
<height>10%</height>
<isEnable>false</isEnable>
</button>
</linearLayout>
</linearLayout>
</linearLayout>
</view>
2.9.2 DM->Controller交互事件数据格式
<?xml version='1.0' encoding='utf-8'?>
<event>
<eventType>connect</eventType>
<devIndex>3</devIndex>
</event>
eventType可选择connect/disconnect/format/datachange
在Controller的eventCallbackForDM中调用。
然后Controller调用getDatatFromDMtoVMForView,组织下一小节中描述的Controller->VM交互请求数据。
mapToUIId标签实现从数据到UI填充的映射。
2.9.3 Controller->VM交互请求数据格式
<?xml version='1.0' encoding='utf-8'?>
<request>
<requestType>createUI</requestType>
<view>
<viewType>mainView</viewType>
<viewId>view_1</viewId>
<viewParentId>desktop</viewParentId>
<devList>
<!—此处的id与viewType定义中的控件对应的id相同,表示填充到对应的id里-->
<id>devList</id>
<mapToUIId>listView_mainView</mapToUIId>
<selectedId>dev_1</selectedId>
<dev>
<id>dev_1</id>
<name>DevStd</name>
<sn>DS20150415</sn>
<imageUrl>$(res)/dev.png</imageUrl>
<otherParamList>
<param1>
<id>param_1</id>
<imageUrl>$(res)/param1.png</imageUrl>
</param1>
<param2>
<id>param_2</id>
<imageUrl>$(res)/param2.png</imageUrl>
</param2>
</otherParamList >
</dev>
</devList>
<button>
<id>btn_change_name</id>
<isEnable>true</isEnable>
</button>
<button>
<id>btn_view_devinfo</id>
<isEnable>true</isEnable>
</button>
<button>
<id>btn_init</id>
<isEnable>true</isEnable>
</button>
</view>
</request>
requestType可以是一些已在概要设计里归纳需要实现的需求,比如createUI、closeUI、showUI、hideUI、updateUI。updateUI中对应的是viewId。当且仅当是createUI需要viewType、viewParent、devId。createUI的返回参数有一个是viewId。
该数据格式在VM的requestCallback中调用。
2.9.4 VM->Controller交互事件数据格式
<?xml version='1.0' encoding='utf-8'?>
<request>
<requestType>updateUI</requestType>
<view>
<viewType>mainView</viewType>
<viewIndex>view_1</viewIndex >
<event>click</event >
<listView>
<id>listView_mainView</id>
<selectedId>param_2</selectedId>
</listView>
</view>
</request>
用户点击了listView的证书节点。
该数据格式在DM的eventCallbackForVM中调用。
用户选择了证书,则提交请求使能证书操作相关按钮。Controller->VM的请求在VM的requestCallback中调用,格式如下:
<?xml version='1.0' encoding='utf-8'?>
<request>
<requestType>updateUI</requestType>
<view>
<viewId>1</viewId>
<viewType>mainView</viewType>
<button>
<id>btn_view_param2</id>
<isEnable>true</isEnable>
</button>
</view>
</request>
用户点击了修改名称按钮。则调用一次VM->Controller的交互事件,声明按钮动作,Controller再提交一次到VM的交互请求:
<?xml version='1.0' encoding='utf-8'?>
<request>
<requestType>createUI</requestType>
<view>
<viewType>changeLabelView</viewType>
<viewId>view_2</viewId>
<devList>
<dev>
<name>dev1</name>
<id>dev1_devStd</id>
<value>devStd</value>
<mapToUIId>oldName</mapToUIId>
</label>
<sn>
<id>DS20150415<id>
<mapToUIId>sn</mapToUIId>
</sn>
</dev>
</devList>
</view>
</request>
用户点击了changeNameView的OK之后,调用一次VM->Controller的交互事件,正式调用修改名称操作。
2.9.5 Controller->DM的交互请求数据格式
<?xml version='1.0' encoding='utf-8'?>
<request>
<requestType>updateDev</requestType>
<dev>
<id>dev1_devStd</id>
</dev>
<action>changeName</action>
<paramList>
<oldName>devStd</oldName>
<newName>devStdNew</newName>
</paramList>
</request>
该消息在DM的requestCallback中调用。
requestCallback处理完之后,如果执行成功,Controller再发一次到VM的更新消息,改变UI显示的Name,并创建一个提示框,提示成功。
3 补充说明:
1、同步异步调用的实现区别:同步:调用者会等待回调结束之后做下一步操作。
异步:调用者请求之后,马上返回。如果有更新的结果,则以事件方式通知Controller。完全不需要在调用者和被调用者创建新的线程来检测。这样做的要求是要在同一进程里。
如果非得是不同进程,可以考虑实现一种RPC远程过程回调。但是目前来看,从之前讨论过的安全性问题来看,应该尽量做到同一进程,然后UI以库形式调用。
2、UI中定义的按钮响应函数处理方法:
所有的按钮功能在Controller中定义,比如修改名称,按照字符串匹配查找相应的函数指针,并填充相应的参数列表。可以统一所有的参数均为字符串。
3、UI中的隐藏:通过Width或者Height更新为0%即可。
至此,可以统一所有的UI请求,不论是不是管理工具发出的,或者即使是安装包的UI,都可以按照这一套来做,完全解耦。全部用XML定义。