UI框架

一个典型的应用界面如下图:

界面右侧,上方蓝框中是一个TabCtrl,下方红框是一个TabLayout布局,TabCtrl显示关联的功能页标题,下方TabLayout为功能页容器,每当创建一个功能页,TabCtrl就增加一项,TabLayout也增加一项容纳功能页。

因为希望能够在尽可能多的地方通过一个简单的函数创建功能页,所以需要把上述的TabCtrl和TabLayout在某处统一管理,接口ITranManager就是为了完成这个功能而定义的。

页面创建


总述

系统中绝大多数功能界面都对应一个功能代码,也叫事务码。事务码是一个字符串,事务码是权限验证的基础,这些事务码都是系统内定的,不可更改。

从开发者角度看,每一个业务功能界面包括两个文件:

  • 一个是XML界面布局文件,负责UI展示
  • 一个是对应的C++功能类,负责处理事件和实现功能

以销售单为例,其对应的XML文件为CDuiPageVa01LS.xml,对应的功能类为CDuiPageVa01LS。

为方便起见,要求XML布局文件名和C++类名一样。

事务码、XML布局、C++类绑定

1、通过宏绑定

开发时,一般是通过CreateTranPage(_T("VA01"),_T("销售订单"))这样的方式启动创建一个功能页面展示出来,第一个参数为事务码,第二个参数为展示出来的描述,如下图:

通过两个C++宏,完成三者的绑定并实现页面的动态创建:

  1. 在C++类的头文件中添加动态创建声明:SOCDECLARE_DYNCREATE(PageClass)
  2. 在C++类的实现文件中添加动态创建实现:SOCIMPLEMENT_DYNCREATE(PageClass, parentClass, TCODEPARAM, _T("xx\\PageClass.xml"))

SOCIMPLEMENT_DYNCREATE有四个参数,第一个为C++类名,第二个为其父类名,第三个为事务码,第四个为绑定的XML文件名。

对于同一个事务码,为了解决如下问题

  • 版本的不同级别界面不同,如T3版本要比T8版本简单,C++类和XML文件都不同,
  • 不同行业界面的C++类不同,如服装行业的类为CDuiPageVax1FZ,而通用行业的类为CDuiPageVax1LS,但使用的都是同一个XML文件

在实现宏的第三个事务码参数TCODEPARAM中,采取三段式结构用来解决上述问题,结构为 TCODE:INDUSTRY:LEVEL,每段含义如下:

  • TCODE:有效的事务码。
  • INDUSTRY:行业代码,如FZ、CM(通用行业)、XC(鞋材行业)、XY(鞋业)等,FZ代表支持颜色尺码的所有行业,包括服装、鞋业、鞋材,鞋业的代码为XY,鞋材的代码为XC,所以FZ包含了XY、XC,如果行业代码设为XY,则只在鞋业版本有效,XC行业无效,软件的行业在编译阶段确定的,也就是调用CGuiVersion::InitGuiVersionEx()时指定了行业和级别。
  • LEVEL:版本级别代码,如V3、V6、V8、T3、T6、T8等,ERP代表 T0-T8 E3-E8等ERP版本,JXC代表V3-V8等进销存版本。

其中后两个字段可以使用通配符*,比如MMF1:*:T3代表任何行业的T3版。MMF1:FZ:*代表服装行业的任何级别版本,其实现逻辑在CDuiTranPageManager::DYNCreatePageControl中。

注意,如果级别使用了通配符而指定了行业代码,如MMF1:FZ:*,则最好对事务码做一个数据库层面的隔离,比如MMF1只能是ERP系统的事务码,而不是进销存的事务码,如果不从数据库层面进行隔离,那么MMF1:FZ:*可能也会在服装行业的进销存中出现,所以要在实施指南的事务码配置中,把MMF1配置为只在ERP中可见。

所以,对ERP和进销存的同一个功能:

  • 如果界面差别较大,则采用不同的事务码,比如物料管理MA01和MMF1就分别属于进销存和ERP,
  • 如果界面一样可以使用相同的事务码,比如很多报表。
  • 如果界面不同,又想使用同一个事务码,只能采取如下通过代码绑定的方式,如库存查询MMBE。

2、通过代码绑定

页面创建的流程如下:

用户点击功能按钮 -> 发送事务码给CMainFrame -> 根据事务码找到对应的XML布局文件 -> 根据XML配置文件创建一个C++功能类对象和一个DuiLib::CControlUI对象并将两者绑定在一起以实现消息接收 -> 展示界面

  • 事务码到XML布局文件的映射

CTrancodeManager的InitTCMap函数中维护了映射关系,如下:

  • 根据XML布局文件绑定C++功能类

在CTrancodeManager的CreatePageControl函数创建功能类并进行绑定,绑定之后,用户界面的消息事件将转发到C++功能类中:

UI框架


CMainFrame

CMainFrame是一个Windows窗口,是DuiLib的主窗口,后面的界面大都是在该窗口上完成绘制。其对应的XML文件为mainframe.xml。

该类首先初始化一个导航控制器:m_navController.Init(CTrancodeManager::GetInstance(),this,&m_PaintManager,pTL,NULL);。

然后导航控制器push进去第一个展示的登录页面;

登录成功后,在登录的C++类CDuiPanelLogon::OnLogonSucceed()中把主界面push进去显示出来