3 皮肤界面
皮肤界面(Skin)是一种通过一系列图片来构成和变换程序界面的机制。皮肤技术使应用程序可以制作出非常漂亮的软件界面。并且应用程序可以通过变换多种皮肤,而拥有不同的外观风格。
MiniGUI 1.3.1版本中新增了对皮肤界面的支持,使应用程序可以方便地利用皮肤技术制作出比较自由的软件界面。本节讲述如何使用MGUtils库所提供的皮肤界面接口来实现应用程序中的皮肤功能。
3.1 皮肤的构成
MiniGUI中的皮肤界面主要由包含在皮肤窗口中的皮肤主界面和各种皮肤元素组成。皮肤窗口是皮肤所依附的窗口,皮肤必须依附在某个窗口上才能显示出来。皮肤主界面又是皮肤元素的依附所在。而皮肤元素是指构成皮肤界面的各种界面元素,包括按钮(button)、标签(label)和滑条(slider)等,当然,它们基本上都是用图片来显示的。
下面的数据结构skin_head_t用来定义一个皮肤。
/** Skin header information structure */
struct skin_head_s
{
/** 皮肤的名称 */
char* name;
/** 皮肤的风格 */
DWORD style;
/** 皮肤及皮肤元素所使用的位图对象数组 */
const BITMAP* bmps;
/** 皮肤所使用的逻辑字体数组 */
const LOGFONT* fonts;
/** 皮肤背景位图对象在位图数组中的索引 */
int bk_bmp_index;
/** 皮肤中皮肤元素的个数 */
int nr_items;
/** 皮肤元素数组 */
skin_item_t* items;
/** 应用程序附加数据 */
DWORD attached;
//……
};
typedef struct skin_head_s skin_head_t;
应用程序在创建一个皮肤窗口之前,应该使用该数据结构定义皮肤窗口所包含皮肤的属性,包括位图资源、逻辑字体、皮肤元素和回调函数等。
name项用来定义皮肤的名字,style项为皮肤的风格,目前只有SKIN_STYLE_TOOLTIP一种,该风格表示皮肤窗口具有显示提示信息的功能。
bmps指向一个位图对象数组,该数组包含了皮肤所使用的所有的位图资源,fonts指向一个逻辑字体数组,该数组包含了皮肤所使用的逻辑字体资源。在使用skin_head_t结构之前,应该先初始化这两个数组中的位图和字体资源,例如从文件中装载。bk_bmp_index定义了皮肤主界面的背景位图对象,它是bmps数组中的索引值。
nr_items和items分别表示皮肤中元素的个数和元素数组,items指向一个skin_item_t类型的数组,该数组定义了皮肤上的所有皮肤元素。皮肤所包含的皮肤元素是应该和skin_head_t结构同时定义好的。
我们使用skin_head_t结构和skin_item_t结构定义了一个皮肤的相关属性之后,该皮肤对象还不是完整的,我们还需要调用skin_init函数对该皮肤对象进行初始化,使该对象包含完整的外部信息和内部数据,之后就可以在窗口中使用该皮肤了。
BOOL skin_init (skin_head_t* skin, skin_event_cb_t event_cb, skin_msg_cb_t msg_cb);
其中event_cb和msg_cb参数指定该皮肤的事件回调函数和消息回调函数。
如果不再需要一个皮肤对象,我们可以使用skin_deinit函数来销毁它。
void skin_deinit (skin_head_t* skin);
皮肤元素是一个皮肤对象的主要组成部分,下面的数据结构skin_item_t定义了一个皮肤元素的属性。
/** Skin item information structure */
typedef struct skin_item_s
{
/** 用来标识皮肤元素*/
int id;
/* 皮肤元素的风格 */
DWORD style;
/** 皮肤元素在皮肤界面中的 X 坐标 */
int x;
/**皮肤元素在皮肤界面中的 Y 坐标 */
int y;
/** 皮肤元素的热点矩形 */
RECT rc_hittest;
/** 皮肤元素位图在皮肤位图数组中的索引 */
int bmp_index;
/** 提示信息文字 */
char* tip;
/** 应用程序附加数据 */
DWORD attached;
/* 定义皮肤元素特定属性的数据 */
void* type_data;
// ……
} skin_item_t;
id 项是一个用来标志皮肤元素的整数,该id值将在事件回调函数中用来判断皮肤事件的元素对象;x和y项为皮肤元素在皮肤界面中的位置;rc_hittest为皮肤元素的热点矩形,如果一个鼠标事件发生在某皮肤元素的热点矩形内,系统将触发一个对应于该皮肤元素的皮肤事件。
几乎每个皮肤及其包含的皮肤界面元素都是通过图片来显示它的外观的,bmp_index指定了皮肤元素所用到的位图对象在皮肤的位图对象数组(skin_head_t结构中的bmps项)中的索引值,皮肤和皮肤界面元素所用到的图片资源应该由应用程序统一装载到皮肤的位图对象数组中。
type_data项定义了皮肤元素特定属性的数据,该指针通常指向一个皮肤元素的属性数据结构,它也是在定义一个皮肤和皮肤元素时应该同时定义好的。例如,对于图片标签元素来说,type_data就是指向一个si_bmplabel_t类型结构的指针,该结构给出了图片标签的标签文字和可选的文字集合等必需的信息。如果皮肤元素是一个MiniGUI控件,那么type_data应该指向一个CTRLDATA类型的结构。
attached为应用程序附加数据项,应用程序可以在该项中存储和某个皮肤元素相关的应用程序附加数据,该数据是应用相关的,由应用程序解释和使用。
style项指定皮肤元素的风格,包括皮肤元素的种类、特定皮肤元素的风格和热点区域的形状等诸多信息,这些不同用途的风格应该使用“|”运算符或上。
皮肤元素的种类是在style项中通过包括相应的元素风格来指定的,MiniGUI有如下几个预定义的皮肤元素:
- SI_TYPE_NRMLABEL:普通标签
- SI_TYPE_BMPLABEL:图片标签
- SI_TYPE_CMDBUTTON:命令按钮
- SI_TYPE_CHKBUTTON:选择按钮
- SI_TYPE_NRMSLIDER:普通滑条
- SI_TYPE_ROTSLIDER:旋转滑条
- SI_TYPE_CONTROL:MiniGUI控件
我们将在本节的稍后部分详细讲述这些皮肤元素的使用。
当皮肤元素的种类为SI_TYPE_CONTROL时,它将是一个MiniGUI控件,例如按钮、静态框等,或者是皮肤子窗口。
皮肤元素的热点区域的形状由如下风格指定:
- SI_TEST_SHAPE_RECT:矩形
- SI_TEST_SHAPE_ELLIPSE:椭圆形
- SI_TEST_SHAPE_LOZENGE:菱形
- SI_TEST_SHAPE_LTRIANGLE:顶点在左边的等腰三角形
- SI_TEST_SHAPE_RTRIANGLE:顶点在右边的等腰三角形
- SI_TEST_SHAPE_UTRIANGLE:顶点在上边的等腰三角形
- SI_TEST_SHAPE_DTRIANGLE:顶点在下边的等腰三角形
皮肤元素的状态由以下风格指定:
- SI_STATUS_VISIBLE:可见
- SI_STATUS_DISABLED:禁用
- SI_STATUS_HILIGHTED:高亮
我们在定义一个皮肤元素时应该指定它的初始状态。此外,特定的皮肤元素还可能有自己特定的状态定义,我们将在下面的皮肤元素中说明。
3.2 皮肤窗口
皮肤窗口是指包含皮肤的MiniGUI窗口,可以是非模态主窗口、模态主窗口和子窗口(控件)。
皮肤主窗口和普通的MiniGUI主窗口的主要区别是外观(皮肤主窗口没有标题栏、边框和系统菜单),皮肤主窗口的事件及消息回调函数和普通主窗口的窗口回调函数的概念类似,用法上有点区别。皮肤子窗口也是一个MiniGUI子窗口(控件),和皮肤主窗口一样,皮肤子窗口可以提供皮肤事件回调函数和MiniGUI消息回调函数。
MiniGUI中皮肤窗口的使用是比较灵活的,普通MiniGUI窗口中可以包含皮肤子窗口,皮肤窗口中也可以包含普通MiniGUI子窗口或者皮肤子窗口。也就是说,皮肤窗口是可以嵌套使用的。
MiniGUI提供了如下用于创建和销毁皮肤窗口的函数:
HWND create_skin_main_window (skin_head_t* skin, HWND hosting, int x, int y, int w, int h, BOOL modal);
HWND create_skin_control (skin_head_t* skin, HWND parent, int id, int x, int y, int w, int h);
void destroy_skin_window (HWND hwnd);
create_skin_main_window函数用于创建具有皮肤界面的主窗口,该主窗口没有标题栏、边框和系统菜单。create_skin_main_window函数的hosting 参数指定了皮肤窗口的宿主窗口;x,y,w,和h参数指定皮肤主窗口的位置和大小;skin参数指定主窗口所包含的皮肤,它是一个指向skin_head_t类型结构的指针,skin_head_t 结构定义了一个皮肤对象的相关数据,该皮肤对象应该是使用skin_init函数初始化好的;如果modal参数为TRUE则创建一个模态主窗口,否则创建一个非模态主窗口。
create_skin_control函数用于创建具有皮肤界面的子窗口,或者说,皮肤控件。parent参数指定了皮肤控件的父窗口;id为控件标志符;x,y,w,h参数指定皮肤控件在其父窗口中的位置和大小。
destroy_skin_window函数用来销毁由create_skin_main_window或create_skin_control创建的皮肤主窗口或子窗口。需要注意的是,销毁一个皮肤窗口并不会销毁它所包含的皮肤对象。
3.3 回调函数的使用
和窗口过程函数的作用类似,回调函数用来处理皮肤及皮肤窗口的皮肤事件和窗口消息。当用户在皮肤窗口上移动或点击鼠标时,例如点击一个按钮皮肤元素,系统将把相应的皮肤事件发送到事件回调函数,把窗口消息发送到消息回调函数。
皮肤的事件回调函数和消息回调函数是在调用skin_create_main_window和skin_create_control函数创建皮肤窗口时通过event_cb和msg_cb参数指定的。皮肤的这两个回调函数还可以通过skin_set_event_cb和skin_set_msg_cb函数来重新设置。
skin_event_cb_t skin_set_event_cb (skin_head_t* skin, skin_event_cb_t event_cb);
skin_msg_cb_t skin_set_msg_cb (skin_head_t* skin, skin_msg_cb_t msg_cb);
skin_event_cb_t为事件回调函数类型,定义如下:
typedef int (* skin_event_cb_t) (HWND hwnd, skin_item_t* item, int event, void* data);
hwnd参数为发生事件的皮肤窗口句柄;item为发生事件的皮肤元素;event为事件类型,data为事件相关数据。一般情况下,我们可以在事件回调函数中通过item所指皮肤元素的id和event的值来判断哪个皮肤元素发生了什么类型的事件。
目前定义的事件类型有:
- SIE_BUTTON_CLICKED:点击按钮
- SIE_SLIDER_CHANGED:滑条的滑块位置变化
- SIE_GAIN_FOCUS:皮肤元素获取焦点(鼠标移动到其上)
- SIE_LOST_FOCUS:皮肤元素失去焦点(鼠标移走)
skin_msg_cb_t为消息回调函数类型,定义如下:
typedef int (* skin_msg_cb_t) (HWND hwnd, int message, WPARAM wparam, LPARAM lparam, int* result);
hwnd参数为发生消息的皮肤窗口句柄,message为消息定义,wparam和lparam为消息参数,result用来返回消息相关的结果。
如果应用程序定义了皮肤窗口的消息回调函数的话,皮肤窗口的窗口过程函数将在处理消息之前先调用皮肤的消息回调函数对该消息进行处理,然后根据消息回调函数的返回值判断是否继续处理该消息。
消息回调函数的返回值包括:
- MSG_CB_GOON:皮肤窗口过程函数将继续处理该消息,result值被忽略
- MSG_CB_DEF_GOON:消息将由MiniGUI缺省窗口过程函数进行处理,result值被忽略
- MSG_CB_STOP:消息的处理将停止,皮肤窗口过程函数返回result所指向的值。
3.4 皮肤操作函数
我们可以通过皮肤操作函数对皮肤或皮肤元素进行一系列通用的操作。
set_window_skin函数可以改变皮肤窗口所包含的皮肤,我们可以通过该函数实现应用程序窗口的换肤功能。
skin_head_t* set_window_skin (HWND hwnd, skin_head_t *new_skin);
hwnd为皮肤窗口的窗口句柄,普通窗口不适用。new_skin为新的皮肤对象,该皮肤必须是已经使用skin_init函数初始化好的。set_window_skin函数返回老的皮肤对象,需要注意的是,该函数并不销毁老的皮肤对象。
get_window_skin函数用来获取皮肤窗口所包含的皮肤。
skin_head_t* get_window_skin (HWND hwnd);
skin_get_item函数可以由皮肤元素的id来获取它的皮肤元素对象。
skin_item_t* skin_get_item (skin_head_t* skin, int id);
skin_get_item_status函数获取皮肤元素的通用状态。通用状态包括可见、禁用和高亮。
DWORD skin_get_item_status (skin_head_t* skin, int id);
skin_get_hilited_item函数用来获取当前高亮的皮肤元素。
skin_item_t* skin_get_hilited_item (skin_head_t* skin);
skin_set_hilited_item函数用来设置当前高亮的皮肤元素。
skin_item_t* skin_set_hilited_item (skin_head_t* skin, int id);
skin_show_item函数用来显示或隐藏一个皮肤元素。
DWORD skin_show_item (skin_head_t* skin, int id, BOOL show);
skin_enable_item函数用来禁用或启用一个皮肤元素。
DWORD skin_enable_item (skin_head_t* skin, int id, BOOL enable);
3.5 普通标签
普通标签是指使用指定逻辑字体显示文字的标签。我们使用skin_item_t结构定义一个普通标签元素时,style项应具有SI_TYPE_NRMLABEL风格;type_data项指向一个si_nrmlabel_t类型的结构,该结构定义了一个普通标签的属性:
/** Normal label item info structure */
typedef struct si_nrmlabel_s
{
/** 标签文字 */
char* label;
/** 正常状态下的标签文字颜色 */
DWORD color;
/** 焦点状态下的标签文字颜色 */
DWORD color_focus;
/** 点击状态下的标签文字颜色*/
DWORD color_click;
/** 标签文字的逻辑字体索引 */
int font_index;
} si_nrmlabel_t;
可以通过skin_get_item_label和skin_set_item_label函数对普通标签进行获取标签名和设置标签名操作。
const char* skin_get_item_label (skin_head_t* skin, int id);
BOOL skin_set_item_label (skin_head_t* skin, int id, const char* label);
这两个函数对图片标签也适用。
3.6 图片标签
图片标签是指使用图片来显示文字或其它字符内容的标签。我们使用skin_item_t结构定义一个图片标签元素时,style项应具有SI_TYPE_BMPLABEL风格;type_data项指向一个si_bmplabel_t类型的结构,该结构定义了一个图片标签的属性:
/** Bitmap label item info structure */
typedef struct si_bmplabel_s
{
/** 标签文字 */
char* label;
/** 标签预定义文字集 */
const char* label_chars;
} si_bmplabel_t;
label字符串为该图片标签所要显示的文字内容; label_chars字符串中包含了图片标签的所有可选文字。
图片标签的文字都是用图片来表示的,这些文字的图片都存储在skin_item_t结构的bmp_index项所指的位图对象中。该位图对象所代表的文字图片需符合如下的要求:
- 文字图片中的文字等距离水平排列,可有多行,但每行不能超过20个字符
- 文字图片中的文字要和label_chars所规定的可选文字完全相符
我们举一个简单的例子。如果要使用一个内容为“21:30”的数码管风格的数字图片标签,图片来自于一个数码管风格的数字及字符图片,如图3.1所示。
图 3.1 图片标签的文字图片
那么该图片标签应该定义如下:
si_bmplabel_t timelabel;
timelabel.label = “21:30”;
label_chars = “0123456789:.”;
可以通过skin_get_item_label和skin_set_item_label函数对图片标签进行获取标签名和设置标签名操作。
3.7 命令按钮
命令按钮是一个和普通的按钮控件作用类似的皮肤元素,它具有正常、按下、高亮和禁用四种状态。我们使用skin_item_t结构定义一个命令按钮时,style项应具有SI_TYPE_CMDBUTTON风格;bmp_index项所表示的图片应包括从左到右依次排列的四个大小相同,分别表示正常、按下、高亮和禁用四种状态的按钮图片,如图3.2所示。
图 3.2 包含四种状态的命令按钮图片
命令按钮有一种特定的状态 SI_BTNSTATUS_CLICKED,表示按钮被按下。
3.8 选择按钮
选择按钮和命令按钮稍有不同,它在点击时会被选中或取消选中,它也具有正常、按下、高亮和禁用四种状态。我们使用skin_item_t结构定义一个选择按钮时,style项应具有SI_TYPE_CHKBUTTON风格;bmp_index项所表示的图片格式和命令按钮是一样的。
选择按钮有一种特定的状态-SI_BTNSTATUS_CHECKED,表示被选中。
我们可以使用skin_get_check_status函数和skin_set_check_status函数来获取和设置选择按钮的当前选中状态。
BOOL skin_get_check_status (skin_head_t* skin, int id);
DWORD skin_set_check_status (skin_head_t* skin, int id, BOOL check);
3.9 普通滑条
普通滑条可以用来表示进度信息。我们使用skin_item_t结构定义一个普通滑条元素时,style项应具有SI_TYPE_NRMSLIDER风格;type_data项指向一个si_nrmslider_t类型的结构,该结构定义了一个普通滑条的属性:
/** Normal slider item info structure */
typedef struct si_nrmslider_s
{
/** The 滑块信息 */
sie_slider_t slider_info;
/** 滑块位图索引 */
int thumb_bmp_index;
} si_nrmslider_t, si_progressbar_t;
sie_slider_t结构用来表示滑块的信息,在定义一个普通滑条时,我们应该同时定义好滑块的最小位置值、最大位置值和当前位置值。
/** Slider information structure */
typedef struct sie_slider_s
{
/** 滑块位置最小值 */
int min_pos;
/* 滑块位置最大值 */
int max_pos;
/* 滑块当前位置值 */
int cur_pos;
} sie_slider_t;
滑条的位图通过skin_item_t结构的bmp_indx项指定,滑块的位图通过si_nrmslider_t结构的thumb_bmp_index项指定,均为皮肤位图数组索引值。
普通滑条具有三种风格:
- SI_NRMSLIDER_HORZ:水平滑条
- SI_NRMSLIDER_VERT:垂直滑条
- SI_NRMSLIDER_STATIC:进度条风格
如果我们需要一个水平方向的进度条,那么定义普通滑条元素的skin_item_t结构的style项需要或上(SI_NRMSLIDER_HORZ | SI_NRMSLIDER_STATIC)。
我们可以通过skin_get_slider_info、skin_set_slider_info和skin_scale_slide_pos等函数获取和设置普通滑条的信息。
BOOL skin_get_slider_info (skin_head_t* skin, int id, sie_slider_t* sie);
BOOL skin_set_slider_info (skin_head_t* skin, int id, const sie_slider_t* sie);
int skin_get_thumb_pos (skin_head_t* skin, int id);
BOOL skin_set_thumb_pos (skin_head_t* skin, int id, int pos);
int skin_scale_slider_pos (const sie_slider_t* org, int new_min, int new_max);
skin_get_slider_info函数用来获取滑块的最小位置值、最大位置值和当前位置值信息,结果存放在一个sie_slider_t类型的结构中;skin_set_slider_info函数重新设置滑条的位置信息;skin_get_thumb_pos和skin_set_thumb_pos函数获取和设置滑块的位置;skin_scale_slider_pos函数用来计算滑条范围缩放后的新位置。
3.10 旋转滑条
旋转滑条和普通滑条类似,不过它的滑块是沿圆弧滑动的。我们使用skin_item_t结构定义一个旋转滑条元素时,style项应具有SI_TYPE_ROTSLIDER风格;type_data项指向一个si_rotslider_t类型的结构,该结构定义了一个旋转滑条的属性:
/** Rotation slider item info structure */
typedef struct si_rotslider_s
{
/** 旋转半径 */
int radius;
/** 开始角度 */
int start_deg;
/** 终止角度 */
int end_deg;
/** 当前角度 */
int cur_pos;
/** 滑块位图索引 */
int thumb_bmp_index;
} si_rotslider_t;
旋转滑块具有三种风格:
- SI_ROTSLIDER_CW:顺时针旋转
- SI_ROTSLIDER_ANTICW:逆时针旋转
- SI_ROTSLIDER_STATIC:进度条风格
和普通滑条一样,我们可以通过skin_get_slider_info、skin_set_slider_info和skin_scale_slide_pos等函数获取和设置旋转滑条的信息。
MiniGUI控件元素表示的就是一个普通的MiniGUI控件。我们使用skin_item_t结构定义一个MiniGUI控件元素时,style项应具有SI_TYPE_CONTROL风格;type_data项指向一个CTRLDATA类型的结构。该元素类型是为了方便用户在皮肤窗口上创建普通MiniGUI控件而设计。
可以使用下面的函数通过皮肤元素的id来获取MiniGUI控件元素的窗口句柄。
HWND skin_get_control_hwnd (skin_head_t* skin, int id);
3.12 编程实例
清单 3.1 所示的程序代码,创建了一个播放器的皮肤界面,它可以响应用户的基本操作。该程序的完整源代码和图片资源可见本指南示例程序包samples 中的 skindemo.c 文件。
清单 3.1 皮肤界面示例程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include <mgutils/mgutils.h>
#define SIID_TITLE 1
#define SIID_PLAY 2
#define SIID_PAUSE 3
#define SIID_STOP 4
#define SIID_PROGRESS 5
#define SIID_SYSMENU 6
#define SIID_CLOSE 7
#define SIID_VOLUME 8
#define SIID_TIMER 9
#define DEF_WIDTH 284
#define DEF_HEIGHT 135
#define ID_TIME 100
/* 定义皮肤元素特定属性 */
static si_nrmslider_t progress = { {0, 180, 0 }, 5 };
static si_nrmslider_t volume = { {1, 100, 50}, 9 };
static si_bmplabel_t timer = { "00:00", "0123456789:-" };
/* 定义皮肤元素数组 */
static skin_item_t skin_main_items [] =
{
{SIID_PLAY, SI_TYPE_CHKBUTTON | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
205, 106, {}, 1, "播放"},
{SIID_PAUSE, SI_TYPE_CHKBUTTON | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
230, 106, {}, 2, "暂停"},
{SIID_STOP, SI_TYPE_CHKBUTTON | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
254, 106, {}, 3, "停止"},
{SIID_PROGRESS, SI_TYPE_NRMSLIDER| SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE
| SI_NRMSLIDER_HORZ, 8, 91, {}, 4, "播放进度" , 0, &progress},
{SIID_SYSMENU, SI_TYPE_CMDBUTTON | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
9, 2, {}, 6},
{SIID_CLOSE, SI_TYPE_CMDBUTTON | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
263, 2, {}, 7, "关闭"},
{SIID_VOLUME, SI_TYPE_NRMSLIDER | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE
| SI_NRMSLIDER_HORZ, 102, 55, {}, 8, "调节音量" , 0, &volume},
{SIID_TIMER, SI_TYPE_BMPLABEL | SI_TEST_SHAPE_RECT | SI_STATUS_VISIBLE,
20, 67, {}, 10, "播放时间", 0, &timer}
};
/* 定义皮肤 */
skin_head_t main_skin =
{
"播放器皮肤窗口",
SKIN_STYLE_TOOLTIP, NULL, NULL,
0, 8, skin_main_items, FALSE
};
/* 位图数组 */
const char *bmp_name[] = {
"main.png", "play.png", "pause.png", "stop.png", "progress-bk.png", "progress.png",
"sysmenu.png", "close.png", "volume-bk.png", "volume.png", "timer.png"
};
static int cur_pos = 0;
/* 位图资源装/卸载函数 */
void load_skin_bmps ( skin_head_t *skin, BOOL load )
{
int i, bmp_num = sizeof(bmp_name)/sizeof(char *);
/* 如果load为真,则将位图装载到skin的bmps数组,否则卸载bmps数组中的位图 */
/* 代码从略... */
}
/* 皮肤事件回调函数 */
static int main_event_cb (HWND hwnd, skin_item_t* item, int event, void* data)
{
if (event == SIE_BUTTON_CLICKED) {
switch (item->id) {
case SIID_PLAY:
/* 皮肤元素SIID_PLAY的SIE_BUTTON_CLICKED事件在这里进行处理 */
...
break;
}
...
}
else if (event == SIE_SLIDER_CHANGED) {
...
}
return 1;
}
/* 皮肤窗口消息回调函数 */
static int msg_event_cb (HWND hwnd, int message, WPARAM wparam, LPARAM lparam, int* result)
{
switch (message) {
case MSG_TIMER:
...
hostskin = get_window_skin (hwnd);
skin_set_thumb_pos (hostskin, SIID_PROGRESS, cur_pos);
skin_set_item_label (hostskin, SIID_TIMER, buf);
break;
}
return 1;
}
int MiniGUIMain (int argc, const char *argv[])
{
MSG msg;
HWND hWndMain;
#ifdef _MGRM_PROCESSES
JoinLayer(NAME_DEF_LAYER, “skindemo”, 0, 0);
#endif
if (!InitMiniGUIExt()) {
return 2;
}
load_skin_bmps (&main_skin, TRUE); /* 装载位图资源 */
if ( !skin_init (&main_skin, main_event_cb, msg_event_cb) ){ /* 初始化皮肤 */
printf ("skin init fail !\n");
}
else{
hWndMain = create_skin_main_window (&main_skin,
HWND_DESKTOP, 100, 100, 100 + 10.DEF_WIDTH, 100 + 10.DEF_HEIGHT, FALSE);
while (GetMessage (&msg, hWndMain)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
MainWindowCleanup (hWndMain);
skin_deinit (&main_skin); /* 撤销皮肤 */
}
load_skin_bmps (&main_skin, FALSE); /* 卸载位图资源 */
MiniGUIExtCleanUp ();
return 0;
}
#ifndef _MGRM_PROCESSES
#include <minigui/dti.c>
#endif
程序定义了一个皮肤窗口main_skin,它包含了八个皮肤元素,包括五个命令按钮,两个普通滑条和一个图片标签。程序首先将皮肤窗口需要的位图资源载入,然后调用skin_init()函数对皮肤进行初始化。如果皮肤初始化成功,则调用create_skin_main_window() 函数创建皮肤窗口,并进入皮肤窗口的消息循环。当程序结束时,需要调用skin_deinit()函数将皮肤撤销。
程序运行界面如图 3.3。
图 3.3 皮肤界面示例
--
KongMing - 19 Jun 2009