文档中心

控件开发_基础

02.控件的共性

控件是人机界面上直接和开发人员交互的部分,不同控件的显示外观各有不同、控件和开发人员的交互方式也多种多样,控件之间还有许多复杂的关系,而且控件系统的设计还要足够的方 便和灵活,使得开发人员界面能够适应各种需求(外观定制、自动布局、多语言翻译)。

控件系统设计的原则是:尽量抽象出各种控件都普遍具有的共性,总结出一套简单的操 作接口,用少量的函数就能够完成大部分的界面开发工作。

各种控件的共性体现在以下几个方面:

1)控件的外观

考察一个无论简单还是复杂的控件或者界面,它在屏幕上的显示都可以看成是若干个矩形显示区域的组合,每个矩形里面可能显示一个图片或一段文字;矩形的位置和大小都可以按照各自所属控件的规则动态改变,显示的内容也可以动态修改。控件系统抽象出显示单元来表示一个矩形显示区域,并且规定每个显示单元上面可以同时显示一个背景(图片或颜色)、一个边框(图片或颜色)、一张图片和多行文本。这样最终一个控件在外观上就是由一个或多个显示单元组成的,如按钮就是一个显示单元;进度条就是由底框、进度和滑块三个显示单元组成;多行列表中的每一个行,每一个单元格都是一个显示单元。

显示单元中的背景、边框、图片的对齐方式、文本的字体,颜色和对齐方式被称为显示单元的风格或样式,可以通过编辑文本文件来设定,开发人员不需要修改程序就可以改变控件中每个显示单元的外观。界面上的多个按钮也可以分别指定不同的风格,如何写风格配置文件以及如何指定风格见下文。

2)控件的状态

每个控件都有四种状态:

1、普通状态:一般控件创建后的状态,用 TW_STATUS_NORMAL表示;

2、活动状态:当鼠标进入或有输入焦点时的状态,用 TW_STATUS_ACTIVE表示;

3、选中状态:当鼠标点击或被选中时的状态,用 TW_STATUS_SELECT表示;

4、无效状态:控件不能接受事件时的状态,比如按钮变灰,用 TW_STATUS_DISABLE表示;

控件在创建时都是普通状态,然后根据设置和控件内部接收到的输入事件自动切换,并 且控件状态的变化通常也会导致显示单元外观的自动变化。

3)控件的创建

除了根窗口控件,其他所有的控件都用一个方法创建:

TWidget *TwCreate(T_ID type, TWidget *parent, Tint x, Tint y, Tint w, Tint h, char *style, Tuint flags);

用 TWidget来表示控件的结构,因为控件也是TD图形软件系统系统用 C语言封装的对象(见《TD图形软件系统开发平台_对象系统》),所以该函数内部其实也是调用了 TObjectCreate()函数来创建的控件对象,并返回控件对象的指针。参数 type是一个字符串 id,标识控件对象的类型,比如创建按钮对象用 TStringID(“button”),创建窗口对象用 TStringID(“window”)。

参数 parent是父控件的指针,参数 x、y、w、h是创建的控件相对于父控件的坐标位置(左上角为(0,0))和大小。从这几个参数可以看出所有的控件对象都组织在一棵控件树上,除了树根,其他所有控件都有父控件,控件可以有任意数目的子控件,父控件相同的控 件互为兄弟控件。根控件是一个窗口类型控件,是控件系统初始化时得到的。

参数 style指定控件显示单元的风格名,同一种类型的控件也可以设定不同的显示风格。(在风格配置文件中,每种风格都可以指定一个名字)。如果 style传为 NULL或者不存 在这个名字的风格,那么就会采用该显示单元的默认风格。最后是 TwCreate()的参数flags,这个参数是控件的标志,每一个标志都是二进制位的掩码,所以可以用’|’运算同时 指定多个标志。标志分为每个控件都具有的公共标志和控件自己的私有标志。

下表列出了每个控件都具有的公共标志:

标志

说明

TW_NO_FOCUS

控件不能得到输入焦点。

TW_CHILD_NO_FOCUS

控件的所有孩子(包括子子孙孙)都不能得到输入焦点。

TW_DISABLE

控件创建时无效。

TW_HIDE

控件创建时隐藏。

TW_LAYOUT_FIX_W

排版控件可能会自动改变其子控件的大小,这两个标

志告诉父控件不要修改我的宽或高

TW_LAYOUT_FIX_H

TW_LAYOUT_FIX_SIZE

TW_LAYOUT_FIX_W|TW_LAYOUT_FIX_H

TW_HIDE_H_SCROLL

当控件有滚动区域时隐藏水平滚动条。

TW_HIDE_V_SCROLL

当控件有滚动区域时隐藏垂直滚动条。

TW_HIDE_SCROLL

TW_HIDE_H_SCROLL|TW_HIDE_V_SCROLL

TW_AUTO_HIDE_H_SCROLL

当控件有滚动区域时,自动隐藏水平滚动条,即滚动

时才显示滚动条,静止时不显示滚动条。

TW_AUTO_HIDE_V_SCROLL

当控件有滚动区域时,自动隐藏垂直滚动条,即滚动

时才显示滚动条,静止时不显示滚动条。

TW_AUTO_HIDE_SCROLL

TW_AUTO_HIDE_H_SCROLL |      TW_AUTO_HIDE_V_SCROLL

TW_NO_H_SCROLL

禁止水平滚动,当然也没有水平滚动条。

TW_NO_V_SCROLL

禁止垂直滚动,当然也没有垂直滚动条。

TW_SCROLL_GRAB_MOUSE

可以手指在滚动区域滑动

TW_NO_EVENT

控件不处理输入事件,只能通过函数接口操作控件

TW_NO_TRANSLATE

控件上的文字不自动翻译

TW_LONG_PRESS_CLICK

控件的 CLICK事件支持长按事件

 

 

控件的公共标志和私有标志都规定了不同的掩码范围,不能冲突。不同控件的私有标志 之间是有可能冲突的。具体见每个控件的头文件。

4)控件的事件

所有控件都具有的事件有:

事件

标识

说明

点击事件

TStringID(“clicked”)

当点击鼠标左键,左键,双击左键,长

按左键或键盘 Enter键时触发

取消事件

TStringID(“escaped”)

当接收到键盘 Escape键时触发

得到焦点事件

TStringID(“got_focus”)

当得到键盘输入焦点时触发

失去焦点事件

TStringID(“lost_focus”)

当失去键盘输入焦点时触发

鼠标进入事件

TStringID(“mouse_enter”)

当鼠标进入控件显示区域时触发

鼠标离开事件

TStringID(“mouse_leave”)

当鼠标离开控件显示区域时触发

修改事件

TStringID(“modified”)

当控件的内容发生变化时触发

销毁事件

TStringID(“destroy”)

当控件被销毁时触发

需要说明以下几点:
a)所有对象在被销毁时都会触发销毁事件,不仅仅是控件对象;
b)点击事件(clicked)有多种发生场景:单击鼠标左键、双击鼠标左键、长按鼠标左键(控件创建时有 TW_LONG_PRESS_CLICK标记)、单击鼠标右键、键盘 Enter建。可以通过函数 TwClickTypeEnum TwGetLastClickType(void) 得到 clicked事件产生的具体原因。注意是在按键松开时产生 clicked事件。
c)修改事件(modified)对不同的控件来说,触发时机不一样,比如按钮控件在状态发生变化时触发,滚动条控件在滑块滑动时触发,窗口控件没有这个事件。注意:用户主动调用某函数导致控件发生改变时,不触发改变事件,比如用户主动设置滚动条的滑块位置不 触发该事件。
d)注册事件及其事件处理和一般的对象相同,见《TD图形软件系统开发平台_对象系统》。
上述这些事件触发时都没有参数。

5)控件的属性和方法

每个控件都具有的属性和相关方法如下表:

属性

相关方法

说明

位置

void TwMove(TWidget *widget, Tint x, Tint y)

设置和获取相对父

控件左上角的坐标

void TwGetPos(TWidget *widget, Tint *x, Tint*y)

void TwGetAbsolutePos(TWidget * widget, int*px, int *py)

得到相对屏幕左上

角的绝对坐标

大小

void TwResize(TWidget *widget, Tint w, Tint h)

设置和获取控件的

大小

void TwGetSize(TWidget *widget, Tint *w, Tint *h)

是否显示

void TwShow(TWidget *widget)

显示控件

void TwHide(TWidget *widget)

隐藏控件

Tbool TwCheckShow(TWidget *widget)

检测是否显示

是否有效

void TwEnable(TWidget *widget)

使控件有效

void TwDisable(TWidget *widget)

使控件无效

Tbool TwCheckEnable(TWidget *widget)

检测是否有效

value (一

个整数值)

Tbool TwSetValue(TWidget *widget, Tint value)

设置一个整数值

Tint TwGetValue(TWidget *widget)

得到一个整数值

caption(一个字符串)

void TwSetCaption(TWidget *widget, const char*string)

设置标题

const char * TwGetCaption(TWidget *widget,Tint *rlen);

得到标题

用 户 附 加数据

void * TwAttachData(TWidget * widget, void *data)

设置和获取控件上附加的用户数据

void * TwGetAttachedData(TWidget *widget)

和 其 他 控件的关系

 

 

TWidget *TwGetParent(TWidget *widget)

得到父控件

TWidget *TwGetChild(TWidget *widget, Tboolif_first)

得到子控件

TWidget *TwGetSibling(TWidget *widget, Tbool if_next)

得到兄弟控件

键 盘 输 入

焦点

void TwSetFocus(TWidget *widget)

设置焦点

TWidget * TwGetFocus(void)

得到当前焦点控件

Tbool TwCheckFocus(TWidget *widget)

检测是否有焦点

需要说明以下几点:

a)整个系统只能有一个控件得到键盘输入焦点,当一个控件得到焦点,那么前一个焦 点控件就会自动失去焦点。

b)控件的用户附加数据完全交给用户负责,控件系统内部不会使用它,初始为 NULL。

c)控件的值(value,一个整数)和标题(caption,一个字符串)是控件的两个特殊属性,不同控件的这两个属性的含义可能不同,也可能有的控件有值没有标题,有的控件有标题没有值。比如:按钮的值就是按钮的状态(普通、活动、选中、无效),按钮的标题就是按钮上显示的文字;进度条的值就是进度,进度条的标题就是上面的文字;窗口控件有标题没有值;

d)当获取父控件、子控件、兄弟控件时,有可能得到一些不是你创建的控件,请不要吃惊,因为有的控件是组合控件,它内部创建了其他控件。比如窗口控件内部可能创建滚动条控件。

e)创建控件时的位置(x,y)和大小(w,h)一般是以像素为单位,父控件的左上角位置为(0,0)。

6)控件的外观设置

前面已经提到所有的控件外观都是由一个或多个显示单元组成的,显示单元就是窗口里面的一个矩形区域,在这个区域中可以显示一个背景(图片或颜色)、一个边框(图片或颜色)、一张图片和多行文本。其中背景、边框、图片的对齐方式、文本的字体、颜色和对齐 方式属于这个显示单元的风格或样式,可以通过一个文本文件来设定。这个文本文件就是风格设置文件,一个简单的例子如下:

#注释(直到换行)
@include “another_style_file” #包含其他的风格设置文件,
window { #设定窗口控件的默认风格
bg="win_bg.png", stretch_tile #设定窗口背景图片,平铺显示
}
button { #设定按钮控件的默认风格
bg=”file1.png”, stretch_hv3 #设定背景图片,采用九宫格拉伸显示方式 text_color=rgb(255,0,0) #设定显示文本的颜色是红色font=”default-12:bold” #设定显示文本的字体名,大小 12像素,加黑text_aline=text_left, text_bottom #设定文字的水平左对齐,垂直下对齐
image_aline=image_top #设定图片为垂直上对齐(水平默认居中对齐)
}
button.ok { #设定风格名为”ok”的按钮控件的风格
[nd] #设定当控件状态是普通和无效时的外观
bg=”normal.png”, stretch_hv3
[as] #设定当控件状态是活动和选中时的外观
bg=”active_png”, stretch_hv3
在一个风格设置文件里可以设置多个风格,也可以包含另一个风格设置文件,另一个文 件名可以是绝对路径,也可以是相对路径(相对于包含它的风格文件所在的路径)
每个风格的格式为:
type 或者 type.name {
[status]
item=value
item=value, value
}

1)type表示该风格对应的控件类型,常用的类型有:

type

说明

button

普通按钮

bool_button

布尔按钮

window

窗口

text

单行文本框

textarea

多行文本框

processbar_h_thumb

水平进度条的滑块

processbar_h_process

水平进度条的进度指示

processbar_h_carrier

水平进度条的背景

processbar_v_thumb

垂直进度条的滑块

processbar_v_process

垂直进度条的进度指示

processbar_v_carrier

垂直进度条的背景

在以后开发新的控件时,也可以动态声明新的风格类型。

2)name表示该风格的名字,如果没有 name,表示该风格是该控件类型的默认外观。

在前面“ 控件的创建” 这一节介绍了 TwCreate()函数的参数 style指明新控件的风格名字,如果不存在该类型的指定名字的风格或者 style为 NULL时,就采用该类型的默认风格。

type和 name一起唯一标识一个风格,当之前已经设定过有相同 type和 name的风 格时,前一个风格的内容将被替换,除非前一个风格的 type前面有一个感叹号!

4)status表示控件的状态,用四个字母 n,a,s,d或者 N,A,S,D分别表示控件的正常(normal)、激活(active)、选中(select)、无效(disable)四个状态。可以同时设定多个状态的风格内容。当没有[status]时,表示设定的是所有状态的风格内容(即等价于[nasd])。

如果一个风格设定中有多个[status]时,注意多个 status不要有重叠,因为重叠的状态只取起前面的。

控件被创建时,状态都是正常(normal),然后才转为其他三个状态,外观也会相应的改为风格中的设定内容,风格中没有设定的内容不会改变。

5)item就是风格中可以设定的项目,value就是项目的值,可以是颜色、图片、整数或字符串。不同的 item会要求不同类型的 value,也可能要求多个 value。item

value

例子

说明

bg

(背景)

颜色

bg=rgb(255,200,200)

 

图片

bg=”bg.png”, stretch_hv3

bg=”None” #特殊图片, 表示没有背景

stretch_hv3 是图 片的 一 种拉 伸 方式

父亲相关

bg=”ParentRelative”

父亲相关模式

img

图片

img=”img.png”

img=”None” #特殊图片, 表示没有

 

border

(边框,大小 可以为 0)

颜色、类型、

大小

border=rgb(255,200,200),border_rect,2

border_rect是一

种边框类型

图片、大小

border=”border.png”,2

边框为 2个像素

border_mar

gin

( 边 框 和 中间 文 本 或 图的 间 距 (上 , 下,左,右四个方向)

1 个整数

border_margin=5

左,上,右,下边都

为 5个像素

2 个整数

border_margin=5,6

左,右为 5;上,下

为 6

3 个整数

border_margin=5,6,7

左为 5;上,下为 6;

右为 7

4 个整数

border_margin=5,6,7,8

左为 5;上为 6;

右为 7;下为 6

text_aline

(文本的对齐方式)

text_left

text_aline=text_left

左对齐,垂直居中

text_right

text_aline=text_top

水平居中,上对齐

text_xfollow

text_aline=text_xfollow,text_top

水 平方 向 在图 片

后面,上对齐

text_top

text_aline=text_top,text_left

上对齐,左对齐

text_bottom

text_aline=text_bottom,text_left

下对齐,左对齐

text_yfollow

text_aline=text_yfollow

垂 直方 向 在图 片

下面,水平居中

image_aline( 图 片 的 对齐方式)

image_left

image_aline=image_left

左对齐,垂直居中

image_right

image_aline=image_right,image_top

右对齐,上对齐

image_top

image_aline=image_top

上对齐,水平居中

image_bott om

image_aline=image_bottom,ima ge_left

下对齐,左对齐

text_margin

一个整数

text_margin=2

两 行文 本 的间 距

为 2个像素

image_margin

一个整数

image_margin=4

当 文本 的 对齐 方式在图片后面时,图 片和 文 本的 间 距为 4个像素

text_color( 文 本 显 示的颜色)

文本颜色

text_color=rgb(0,0,0)

黑色文本

文本颜色,文本背景颜色

text_color=rgb(0,0,0),rgb(0,255,0)

黑色文本,并且文本的背景为绿色

font

(文本显示的字体)

一个表示字体

名的字符串

font=”default-16”

默认字体,大小为16像素

font=”yahei-16:bold”

字体名”yahei”,16像素,加黑

风格中出现的图片文件的路径都是相对于该风格文件所在的目录。

当背景是图片时,因为图片的大小和显示单元的大小可能不一致,所以需要拉伸显示, 拉伸的方式有:

图片对齐方式

说明

stretch_normal

普通拉伸(水平和垂直方向都放大或缩小)

stretch_hv3

把图片切为 3x3的 9块,4个角的不拉伸,四个边块水平或垂直拉

伸,中间块普通拉伸。

stretch_hv2

把图片切为 2x2的 4块,4个角的不拉伸,对两条分隔线及其交叉

点进行拉伸。

stretch_tile

平铺,不拉伸。

注意:窗口的背景图片只能是平铺,窗口没有前景图片。前景图片只能是普通拉伸。

背景可以设置成一种特殊的模式:“ ParentRelative”(父亲相关模式),这种模式下的背景和父窗口的背景相同,常用于滚动显示区域时保持背景不滚动。

风格中设定的边框类型目前有:

边框类型

说明

border_rect

简单矩形边框

border_circle

圆角边框

border_down

凹边框

border_up

凸边框

border_right_br

下边和右边有线条的边框

border_right_b

下划线边框

border_right_b_d

下划线虚边框

border_blank

空白框,不显示任何线条,只用来占位

必须要先加载风格设置文件,才能创建使用其中的风格:

void TwStyleParseFile(const char *file) //加载风格文件
例子:
TwStyleParseFile(“/some/path/style.rc”);
文件名可以是绝对路径,也可以是相对路径,但是当程序的路径不固定,并且程序运行
时的当前路径也不固定时,那么绝对路径和相对路径都无法确定。这时就可以使用在《TD图形软件系统开发平台_基础》讲到的获取程序绝对路径的函数,来确定风格文件的路径:
/* 假定程序为/some/path/bin/file1,风格文件为/some/path/style/file2 */
TwStyleParseFile(TGetExecutePath(“../style/file2”));
7)多语言支持

多语言支持是指在用户界面上显示的静态文本能够根据当前的语言环境,自动显示为翻
译后的文本内容,用户程序不需要改动。TD图形软件系统控件系统的多语言支持类似于 Linux下的GetText机制。首先需要用户先编辑一个翻译文件,文件的内容如下:
“string1”=”字符串 1”
“string2”=”字符串 2”
“ok”=”确定”
即每一行是一项翻译,等号前面是程序中出现的字符串,等号后面是翻译后的文本串。 注意:该翻译文件的编码必须是 UTF-8。
然后加载翻译文件:

void TwTransParseFile(const char * file);
/* 假定程序为/some/path/bin/file1,翻译文件为/some/path/trans/file3 */
TwTransParseFile(TGetExecutePath(“../trans/file3”));
该函数可以调用多次加载多个翻译文件,但是如果等号左边的字符串重复了,将忽略这一行。当用户需要得到某个字符串 string的翻译结果时,调用下面的函数:
const char * TwTrans(const char * string);
例如:TwTrans("ok"); //把”ok”翻译成等号右边的内容(”确定”)
注意:当翻译文件中不存在要翻译的字符串时,twTrans()就返回参数 string。
注意:设置到控件上显示的文字,控件内部都会调用 twTrans()函数来自动翻译,即 TwSetCaption(button_ok, "ok")按钮上显示的文字是”ok”被翻译的内容。
8)示例

最后还有几个常用的全局函数:

TWidget *TwAppInit(void); //控件系统初始化,返回根窗口控件
void TwMainLoop(void); //控件系统的事件循环,内部其实就是调用:
//while(1) TTaskLoopOnce(0);
void TwUpdateShow(void); //立即更新界面的显示
当调用某些函数导致控件外观发生变化时,界面并没有立即更新,而是等到一轮事件都
处理完毕后才一起自动刷新,这样可以提高系统的性能。用户也可以调用 TwUpdateShow()立即更新界面显示。
通过上述统一的方法调用和事件就可以完成界面编程开发的大部分工作,比如一个完整 的 hello例子:
#include <TWidget/TWidget.h> //包含控件系统的头文件
TWidget *root, *mainwindow, *button_ok, *button_cancel; //定义用到的控件 指针
void cancel_click_callback(void *obj, T_ID event, TTable *in, void *arg, TExist *exist) {
exit(0); //退出程序
}
void ok_click_callback(void *obj, T_ID event, TTable *in, void *arg, TExist *exist) {
TLogD("you have click button %s\n", TwGetCaption(obj, NULL));
}
int main(int argc, char **argv)
{
root = TwAppInit(); //初始化控件系统,得到根窗口指针
TwStyleParseFile(TGetExecutePath(“../style/style.rc”); //加载风格文件,可 以没有
TwTransParseFile(TGetExecutePath(“../trans/trans.rc”); //加载翻译文件, 可以没有
//创建主窗口,设置标题
mainwindow = TwCreate(TW_WINDOW, root, 20, 20, 200, 100, NULL, 0);
TwSetCaption(mainwindow, "hello");
//创建按钮,设置标题,注册事件
button_ok = TwCreate(TW_BUTTON, mainwindow, 20, 20, 50, 30, NULL, 0);