具体实施方式
本发明提供一种跨CPU平台的嵌入式图形界面生成器,结构参见图1,设计流程参见图2。首先使用者通过设计环境进行设计,系统对设计结果进行描述(步骤101);生成器对描述文件进行解析,解析结果处理成目标平台相关的格式(步骤102);根据解析结果和平台特征,生成和组织源代码(步骤103);将源代码编译成和目标CPU平台相关的指令集(步骤104);生成的指令集下载到目标平台运行(步骤105)。
如图3所示,通过硬件描述层(HIUD)对硬件驱动进行抽象,由HIUD层完成底层驱动的调用,实现GUI内核的硬件无关性,方便移植。HIUD定义一个统一的接口供GUI内核和其他部分调用,并负责根据不同的CPU平台分别实现定义的接口功能。
GUI的图形库实现基本图形绘制,主要包括点、直线、矩形绘制与填充、圆形绘制与填充、椭圆绘制与填充、多边形绘制与填充、弧线、位图显示、网格(表格)绘制、矩形区域反相显示。字库实现方法为把每种字符类型(字体+字号)的字符集合按字符编码升序排序组成一个数组。当要显示一个字符时,可使用折半查找快速的找到要显示的字符的信息。字库数据结构包括字模结构、字符信息结构、字符信息数组、字体。字模结构是一个一维数组,数组的大小视字体不同的宽度和高度而定。设字体的宽度为w象素,高度为h象素,则数组的大小为(w*h/8)字节。因此可以看出,数组中每一位表示一个象素,用1表示字符笔划经过该象素(在显示的时候将被填上画笔的颜色),0表示不经过(在显示的时候不填色,即显示背景色)。图4显示了一个“大”(16×16)字的结构。
字符信息包含字符的编码、宽度(像素)、每行的字节数和字模所在地址,只包含字符的宽度而不包含高度,是假设同一字体的所有字符都是等高的。因此,有如下的字符信息结构:
typedef struct{
U16 inCode;
U8 xSize;
U8 bytePLine;
U8*pCharData;
}sGUI_CharInfo;
其中,inCode是字符的编码;xSize表示字符的宽度(象素);bytePLine是字符的行数据(字节为单位);pCharData表示字模的地址。如“大”字的字符信息结构为:
{0xb4f3,16,2,acFontHZSong_16_b4f3},/*大96*/
“大”字的编码为0xb4f3,字符宽度为16,每行要2个字节的数据。
字符信息数组一个字符信息数组是该类型的所有字符按编码升序排序后的数组。其定义形式如下:
static sGUI_CharInfo sGUI_FontSong_16_CharInfo[]={
{0x0021,8,1,acFontHZSong_16_0021},/*!0*/
{0x0022,8,1,acFontHZSong_16_0022},/*″1*/
{0x0023,8,1,acFontHZSong_16_0023},/*#2*/
{0x0024,8,1,acFontHZSong_16_0024},/*$3*/
{0x0025,8,1,acFontHZSong_16_0025},/*%4*/
{0x0026,8,1,acFontHZSong_16_0026},/*&5*/
{0x0027,8,1,acFontHZSong_16_0027},/*′6*/
{0x0028,8,1,acFontHZSong_16_0028},/*(7*/
{0x0029,8,1,acFontHZSong_16_0029},/*)8*/
{0x002a,8,1,acFontHZSong_16_002a},/**9*/
{0x002b,8,1,acFontHZSong_16_002b},/*+10*/
{0x002c,8,1,acFontHZSong_16_002c},/*,11*/
{0x002d,8,1,acFontHZSong_16_002d},/*-12*/
{0x002e,8,1,acFontHZSong_16_002e},/*.13*/
{0x002f,8,1,acFontHZSong_16_002f},/*/14*/
{0x0030,8,1,acFontHZSong_16_0030},/*0 15*/
{0x0031,8,1,acFontHZSong_16_0031},/*1 16*/
{0x0032,8,1,acFontHZSong_16_0032},/*2 17*/
字体结构包含字符的高度信息(规定同一字体的字符的高度是相同的)、字符信息数组的地址以及数组中元素的个数。由此可定义字体结构如下:
typedef struct
{
U8 ySize;
const sGUI_CharInfo* pCharList;
int charNum;
}sGUI_Font;
其中,ySize表示字符的高度;pCharList是字符信息数组的地址;charNum是数组中元素的个数。
消息队列是顺序表示(即数组表示)的循环队列,消息结构如下:
typedef struct
{
union{
const void*p;
int v;
} data;
sGUI_Handle hObjDst;
sGUI_Handle hObjSrc;
U16 msgId;
}sGUI_Msg;
其中,msgId表示的是消息的类型,比如MSG_TOUCH_STATE_DOWN表示触摸屏被触摸(按下),MSG_SHOW表示显示窗体的消息等;hWinDst则表示接收并处理消息的目标窗体;hObjSrc表示发送消息的对象;data字段是一个联合体,其成员包含一个void*类型的指针p和一个int型的变量v,通过它们可以用来传递消息所包含的数据。
定义好消息结构以后,就可以定义消息队列控制结构了。首先定义消息队列长度。消息队列的控制结构采用“模板”方式,只描述通用数据类型。定义好队列控制结构后,用一个真正的队列(数组)来存放消息具体的消息。消息队列的数据结构定义好后就可以对消息进行管理了,包括消息队列的初始化,消息入队列,消息出队列,判断消息队列是否为空,发送消息,消息派送等操作。消息队列的初始化,主要是将队列控制结构初始化。另外,发送消息实际上就是将消息入队,而消息派送则是将消息真正的发给处理它的窗体或控件来处理。
应用程序进入循环以后,GUI系统开始执行,在这个过程中,由于某些原因产生并发送了消息(主要包括:触摸屏按下抬起消息,退出系统消息,重画控件消息,控件获得失去焦点消息,按键消息,窗体移动消息,窗体显示隐藏消息,用户自定义消息等),这些消息先被寄存在消息队列中。一旦触发消息处理函数,该函数将对本次收集的消息进行一次集中处理,直到消息队列空为止。如果有需要,可以在任意的地方手动触发消息处理函数,这样可以及时的处理需要处理的消息,提高效率。
控件库包含常用的控件和操作,如控件移动,控件隐藏显示、按钮动态效果,编辑框软键盘输入。控件的工作原理是:首先创建控件,主要是为控件分配内存空间,设置控件的初始属性和状态及默认属性和状态,设置控件的默认回调函数用以处理一些默认的消息,把控件加入控件管理链表。控件创建成功后,返回控件的句柄。在以后的程序中就是通过这个句柄来操作控件的,包括向控件发送消息,改变控件的属性值等。在内存管理模块中提到句柄与真实地址转换的过程,当向控件派送消息或改变控件的属性时,首先根据句柄得到相应的对象在内存中的真实地址(指针),通过这个指针操作对象的属性,包括调用默认的回调函数来处理消息。这样就完成消息处理机制了。
常用控件的对象结构是大部分有形控件的基础设施,主要用于实现对象的管理及包含一些公共属性。其中包含了对象的矩形区域、唯一标识、默认的消息处理函数的函数指针以及键盘、鼠标、触摸屏消息处理函数指针和对象链表指针。对象结构定义如下:
typedef struct
{
int id;
sGUI_CALLBACK cbDefault;
sGUI_KeyEventHandlers cbKey;
sGUI_TouchEventHandlers cbTouch;
sGUI_MouseEventHandlers cbMouse;
sGUI_Handle hParent;
sGUI_Handle hFirstChild;
sGUI_Handle hNextSibling;
sGUI_Rect rect;
U16 status;
double curPx;
double curPy;
}sGUI_Obj;
操作描述包括操作发出对象结构描述,若采用键盘操作为按键信息结构;若采用触摸屏操作为触摸操作信息结构;若采用鼠标操作为鼠标操作信息结构。还包括三类操作类型对应的消息回调函数类型,用来对自定义控件的操作进行处理。另外,需要保存对象的状态,包括可见、无效和无用三种状态,可见状态表示对应的控件是否可见;无效表示控件已失效,需要重画;无用状态表示控件不可用。控件对象管理完成对象之间的关系描述,通过一棵弟兄二叉树表现这些关系。在创建一个控件时,需要指定控件的父控件。如果父控件为0,则表示创建的是第一个控件。否则,把控件插入父控件的所有子控件队列的尾部。因此形成了一棵弟兄二叉树,其级别结构如下如图5所示。
执行模块驱动整个GUI的工作,包括定时器的执行、触摸屏的执行、键盘、窗体模块的执行、和LCD模块的执行。GUI的执行流程如图6所示。
生成器解析部分首先读取XML描述文件,通过遍历整个XML文件所有节点和子节点,获取使用者设计信息,包括图形界面、事件和通信等,图形界面有窗体和窗体中的控件,以及控件的属性组成。解析后获取的结果作为代码生成的依据。组织部分根据解析结果,调用和平台相关的模板文件,分类生成各个模块的源代码;再把生成的源代码组织成工程中的各个源代码文件。对生成的源代码文件,调用目标平台编译器编译成可执行指令集。
以上所述仅为本发明一个实施例,当不能以此限制本发明范围,凡依据本发明所做的结构上的变化、功能模块的增删,只要不失本发明的要义所在,都应视为落入本发明保护范围之内受到制约。