软键盘产品界面显示的通用程序设计
软键盘产品界面显示的通用程序设计 关键词:状态图 控制类产品 界面 数据结构 可视频程序的一个重要特点是:有大量的窗口、对话框等界面与用户进行 交互,并根据用户在界面上的操作进行相应的事务处理。设计良好的用户界面不 仅可以提高用户与软件的交互效率,而且可以减少用户操作与控制状态转换出错 的概率。好的设计界面不但要注意屏幕布局,更在充分理解待完成工作的基础上, 快速地构架系统的有效结构,使编程人员有更多的精力去实现系统的处理功能。下面介绍一种在Nucleus仿真器MNT中快速实现产品界面设计的经验。
图1 PDA产品的主界面和部分功能操作界面 1 系统分析 (1)问题的由来 美国ATI公司的Nucleus嵌入式操作系统是一个嵌入式系统开发包。该软件 包借助Visual C++的调试器和编译器进行程序的调试与编译,基本控制语句标准 C语句。使用其中的Nucleus MNT仿真器提供的专用库函数,可以实现产品开发。
为了编写PDA的控制软件,首先分析整个产品的功能,并以状态转换图进 行描述。图2是系统记事本部分状态转换图。
2 系统的实现 2.1 数据结构的建立 通过对状态图的分析得知,整个系统有38种功能不同的控件,共70个。在 不同的界面上发生的不同控制行为决定了系统的不同转移状态,并启动响应事务 处理。假设全部的数据结构预先定义在pda_init.h文件中,为了完成系统设计,主 要需要设计如下数据结构:控件数组、状态控件链、显示状态链、显示状态栈。
(1)控件数组 在Nucleus MNT中,用Window CreateWindow(int wClass,char*ttl,int x,int y,int w,int h,int(*wndProc)(),unsigned long attrib)和CTRL *Control(Window wnd,int type,char name[],int x,int y,int w,int h,int id)函数,可分别创建窗口窗的各种控件,所以设计了一个二维int型控件数组。其中存储的是70个控件的相关参数,函数调 用时,直接引用控件数组的不同分量就可以显示出不同的控制界面。控件数组的 定义格式为:static int Controls[70][7];
Controls[X][0]:控件属性,表示控件的类型。例如,0表示按钮,13表示 文本输入框,23表示图片,29表示静态文本框,51表示中英字符的三块键盘,52 表示数字小键盘,53表示号码查询键盘,54表示计算器键盘。
Controls[X][1]:控件偏移植。作用是区分或设定同一类型不同控件的编号。
编号从0开始。例如,对于系统中的17个按钮可分别设置为 {0,0,50,110,60,20,5501}, {0,1,150,110,60,20,5502}, …… {0,16,230,160,35,40,5517} 系统的21个静态文本框分别设置为 {29,17,10,15,50,30,5601}, {29,35,10,40,50,30,5619}, …… {29,38,10,15,50,30,5622}, 偏移值指定的内容是需要显示的字符串,如图3所示。
Controls[X][2]:控件距所处窗处左边界的距离。
Controls[X][3]:控件距所处窗体右边界的距离。
Controls[X][4]:控件的宽度。
Controls[X][5]:控件的高度。
Controls[X][6]:控件的标识号码,为了系统调用方便而取的编号。
图4 界面控件链(2)状态控件链 控件链(static int StateControlList[53][6])是一个动态的单向链表结构。在 应用程序初始化阶段,根据对pda_init.h文件中定义的界面控件静态数组的遍历动 态生成。当程序进入某个界面时,只要循环显示该链表中的控件即可。
Static int StateControlList[53][6]数组的具体定义格式如下:
其中“控件1”、“控件2”……表示当前状态的第一、第二等控件。数据“46” 表示控件数组的第47个控件,与Controls[46][Y]数组中的内容相对应。“0”是控件 结束标志,“NULL”表示没有数据。
为了处理方面,在程序初始化的过程中,假设这个静态数组生成了一个单 向链表数组,PDAStateControlsList[53]。具体格式如图4所示。
该链表的每个节点是一个pdacontrolslist型常量,具体结构如下:
struct pdacontrolslist //以下的“X”为控件数组的编号 { int propertyvalue;
//控件属性值,大小等于Controls[X][0] int default_flag;
//缺省偏移值,大小等于Controls[X][1] int x;
//控件距窗体左边界位置,大小等于Controls[X][2] int y;
//控件距离窗体上边界位置,大小等于Controls[X][3] in w;
//控件宽度,大小等于Controls[X][4] int h;
//控件高度,大小等于Controls[X][5] int idvalue;
//控件的id值,大小等于Controls[X][6] struct pdacontrolslist *next;
//指向下一条记录 };(3)显示状态链 系统各种状态之间的转换用显示状态链(static int ShowStateList[22][11])进 行控制。它是一个动态结构的双向链表,在应用程序初始化阶段,遍历pda_init.h 文件中定义的状态转换顺序静态数组,动态生成该状态链。这种数据结构为电话 簿和记事本的添加和修改操作提供了方便。由于电话簿和记事本的操作状态转换 是单向的,所以采用双向链表结构实现线性状态的前后续状态转换。
Static int ShowStateList[22][11]数组的具体定义格式如下:
其中“状态1,2,3……”依次表示当前状态链的不同状态。“0”是结束标志, “NULL”表示没有数据。
在程序初始化的过程中,由这个静态数组生成一个双向链表数组 OperationStates[22]。双向链表的每个节点数据域是一个整型常量。它的值等于与 其相对应的状态控件链数组(PDAStateControlsList[53])的下标值。例如,如果 节点的数据域为12,则对应PDAStateControlsList[12]状态控件链。具体的生成格 式如图5所示。
(4)显示状态栈 显示状态栈存放的数据是显示状态编号。具体数据是从初始状态到达当前 状态所经过的所有状态,栈数据处理由int StateStackPop()、intStateStackGet()、 void StateStackPush(int a)三个函数实现。具体处理情况如图6所示。
1.2 编程实现 有了以上一套数据结构之后,具体编写程序代码时,根据不同功能所要完 成的任务和使用的数据结构,可归类待编写模块,从而提供代码复用率。如电话 簿和记事本就可以共用同一套程序代码。因此,关于PDA的所有系统模块划分如 图7所示。
系统各个模块间的连接用状态栈以及一些公共变量实现,根据状态栈的信 息确定工作到了哪个状态,根据公共变量获得完成操作所需要的信息。程序每进 入一个新模块调用的通用处理函数,先屏蔽主界面上固定键盘内的所有按钮,再 显示本界面的按钮,最后将固定按钮连接到进入模块的处理函数中,实现固定键盘操作含义的转变。
3 小结 利用状态图分析和以上定义的数据结构,可以进行任何界面的显示。这种 编程方法有两大优点。
①快速方便地完成界面的任意修改。当需要改变界面时,只要改变控制数 组中的值和控件静态数组中的值即可,无需修改任何代码。
②扩展嵌入式系统功能。只要进一步进行状态图分析,把新功能的状态顺 序关系填写到状态链数组中,就可以完成新功能的进入和返回。