五个演员
这篇文章的标题并非暗示我要写一篇影视娱乐方面的文章,它只是表示我将“Actor”这个英文单词翻译成了中文。本文主要介绍 Clutter 库提供的五个基本的 Actor 的用法。
矩形
ClutterRectangle [1] 的主要功能是在 Stage 上显示一个有边框可填充的的矩形。看下面的示例:
#include <clutter/clutter.h> int main(int argc, char *argv[]) { if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff }; ClutterColor rect_area_color = { 0xff, 0xe6, 0xe6, 0xff }; ClutterColor rect_border_color = { 0xa0, 0x00, 0x00, 0xff }; /* 获取默认的 Stage 并设置其尺寸与颜色 */ ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Rectangle!"); clutter_actor_set_size (stage, 400, 200); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* 构建矩形 Actor */ ClutterActor *rectangle = clutter_rectangle_new_with_color (&rect_area_color); clutter_actor_set_size (rectangle, 100, 50); clutter_actor_set_position (rectangle, 150, 75); clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 4); clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), &rect_border_color); clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle); /* 显示 Stage 及其子对象(矩形 Actor) */ clutter_actor_show_all (stage); /* 开启 Clutter 主循环,响应事件 */ clutter_main (); return 0; }
上述代码构建了一个长为 400,宽为 200 的 Stage,并在其上(垂直屏幕向外的方向)摆放了一个位置居中(通过丑陋的硬编码实现)的长为 100,宽为 50 的矩形 Actor,如下图所示:
上述代码中构建 Stage 的部分与文献 [2] 大同小异。
代码块:
ClutterActor *rectangle = clutter_rectangle_new_with_color (&rectangle_color);
用于构建一个填充了颜色的矩形 Actor。
由于 ClutterRectangle 也是 ClutterActor 的子类,因此可以使用 ClutterActor 的的大部分方法,例如可使用 clutter_actor_set_size() 函数与 clutter_actor_set_position() 函数设置矩形 Actor 的尺寸与位置,即:
clutter_actor_set_size (rectangle, 100, 50); clutter_actor_set_position (rectangle, 150, 75);
ClutterRectangle 类也实现了自己的一些方法,例如 clutter_rectangle_set_border_width() 和 clutter_rectangle_set_border_color() 函数可以设置矩形 Actor 对象的边界宽度与颜色:
clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 4); clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), &rect_border_color);
对于所有需要在 Stage 上显示的 Actor,都需要使用 ClutterContainer 接口 [3] 提供的 clutter_container_add_actor() 函数将 Actor 添加到 Stage 中,例如:
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rectangle);
之所以能够对 Stage 对象使用 ClutterContainer 接口,是因为 ClutterStage 实现了 ClutterContainer 接口,若要深入了解其中原理,可能你需要阅读 [4, 5]。
需要注意的是,上述示例使用了 clutter_actor_show_all() 函数显示 Stage 和矩形 Actor,而不是像文献 [1] 中使用 clutter_actor_show() 函数。那么 clutter_actor_show() 与 clutter_actor_show_all() 有什么区别?
clutter_actor_show() 只是用于标定一个 Actor 可以被显示,它的对立者是 clutter_actor_hide() 函数,后者是用于标定一个 Actor 不会被显示。事实上,Actor 默认就是可以被显示的,所以无需要每构建一个 Actor 之后就使用 clutter_actor_show() 来标定它。但是,当 clutter_actor_show() 遇到的 Actor 是 Stage 时,那么它就会将 Stage 及其所包含的各个可被显示的子 Actor 对象(即 clutter_container_add_actor() 所添加的 Actor 对象)一并显示。
clutter_actor_show_all () 是用于将一个实现了 ClutterContainer 接口的对象(例如 Stage)及其子 Actor 对象全部显示出来,即便其中某个子 Actor 对象使用了 clutter_actor_hide() 将其标定为不被显示,它也无法遁形。
文本
ClutterText [6] 的主要功能显示与编辑文本。看下面的示例:
#include <clutter/clutter.h> int main(int argc, char *argv[]) { if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff }; ClutterColor text_color = { 0xff, 0xe6, 0xe6, 0xff }; /* 获取默认的 Stage 并设置其尺寸与颜色 */ ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Text!"); clutter_actor_set_size (stage, 400, 200); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* 构建文本 Actor */ ClutterActor *text = clutter_text_new_with_text ("Sans 12", "中国人指望政府\n" "美国人指望 X 战警"); clutter_actor_set_position (text, 140, 70); clutter_text_set_color (CLUTTER_TEXT (text), &text_color); clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER); clutter_container_add_actor (CLUTTER_CONTAINER (stage), text); /* 显示 Stage 及其子 Actor 对象 */ clutter_actor_show_all (stage); /* 开启 Clutter 主循环,响应事件 */ clutter_main (); return 0; }
上面的代码在构建及显示 Stage 部分与上一节的示例差不多,只是将矩形 Actor 的构建部分替换为了文本 Actor 的构建,关键代码如下:
ClutterActor *text = clutter_text_new_with_text ("Sans 12", "中国人指望政府\n" "美国人指望 X 战警"); clutter_actor_set_position (text, 140, 70); clutter_text_set_color (CLUTTER_TEXT (text), &text_color); clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER);
其中 clutter_text_new_with_text() 用于创建一个文本 Actor 对象并赋予它要使用的字体及文本数据;clutter_actor_set_position() 对文本 Actor 在其父 Actor 对象(本例是 Stage)上寻找摆放位置;clutter_text_set_color() 与 clutter_text_set_line_alignment() 分别用于设定文本颜色与对齐格式。
上例构建的 Stage 与文本 Actor 如下图所示:
注意代码中 clutter_text_set_line_alignment() 的第二个参数“PANGO_ALIGN_CENTER”,该参数表示将文本行设为居中对齐,并且暗示了 Clutter 库在文本 Actor 的实现中借助了 Pango 库 [7]。
纹理
在 OpenGL 的概念里,纹理就是附着在几何模型表面的图片。Clutter 的 ClutterTexture [8] 利用了 OpenGL 的纹理映射功能,可以实现图片(像素格式)的显示和操作。看下面的示例:
#include <clutter/clutter.h> int main(int argc, char *argv[]) { if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff }; /* 获取默认的 Stage 并设置其尺寸与颜色 */ ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Texture!"); clutter_actor_set_size (stage, 400, 200); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* 构建纹理 Actor */ ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE); clutter_actor_set_request_mode (image, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT); clutter_actor_set_height (image, 150); clutter_actor_set_position (image, 83, 25); clutter_container_add_actor (CLUTTER_CONTAINER (stage), image); /* 显示 Stage 及其子 Actor 对象 */ clutter_actor_show_all (stage); /* 开启 Clutter 主循环,响应事件 */ clutter_main (); return 0; }
上述代码是在 Stage 中显示『V 字仇杀队』的一张剧照素材图片见 [9],效果如下图所示:
程序中与构建纹理 Actor 相关的代码主要是:
ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE); clutter_actor_set_request_mode (image, CLUTTER_REQUEST_WIDTH_FOR_HEIGHT); clutter_actor_set_height (image, 150); clutter_actor_set_position (image, 83, 25);
其中,clutter_texture_new_from_file() 可以从图片文件创建纹理 Actor 对象;clutter_texture_set_keep_aspect_ratio() 用于设定纹理 Actor 对象的纵横比保持与原始图片相同,并通过与 clutter_actor_set_request_mode() 与 clutter_actor_set_height() 的配合,可以实现将纹理 Actor 对象在不发生拉伸或压缩的前提下,在 Stage 中显示与原始图片成比例的图形。最后,根据图片的纵横比和纹理 Actor 对象的宽度和高度,计算出可以让纹理 Actor 对象居于 Stage 中心的坐标位置 (83, 25),使用 clutter_actor_set_position() 对纹理 Actor 对象进行定位。
克隆
考虑这样一个问题:对于上一节通过载入图片文件而构成的纹理 Actor 对象,如何将其复制一份,构成一个新的 Actor 对象,并进行一些操作(例如平移、旋转等)?
当然,如果再次载入一次图片文件以构建一个新的纹理 Actor 对象可以解决上述问题,但是文件的读取是非常耗费资源。为了更好的解决这个问题,Clutter 库提供了 ClutterClone 类 [10],它可以有效的复制各种 Actor 对象。看下面的示例:
#include <clutter/clutter.h> int main(int argc, char *argv[]) { if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff }; /* 获取默认的 Stage 并设置其尺寸与颜色 */ ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Clone!"); clutter_actor_set_size (stage, 400, 200); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* 构建纹理 Actor */ ClutterActor *image = clutter_texture_new_from_file ("v.jpg", NULL); clutter_texture_set_keep_aspect_ratio (CLUTTER_TEXTURE (image), TRUE); clutter_actor_set_request_mode (image, CLUTTER_REQUEST_HEIGHT_FOR_WIDTH); clutter_actor_set_width (image, 200); clutter_actor_set_position (image, 0, 36.5); clutter_container_add_actor (CLUTTER_CONTAINER (stage), image); /* 复制 Texture Actor */ ClutterActor *image_clone = clutter_clone_new (image); clutter_actor_set_position (image_clone, 200, 36.5); clutter_container_add_actor (CLUTTER_CONTAINER (stage), image_clone); /* 显示 Stage 及其子 Actor 对象 */ clutter_actor_show_all (stage); /* 开启 Clutter 主循环,响应事件 */ clutter_main (); return 0; }
上面的代码与 ClutterClone 相关的代码主要如下:
ClutterActor *image_clone = clutter_clone_new (image); clutter_actor_set_position (image_clone, 200, 36.5);
其中 clutter_clone_new() 可从已建立的纹理 Actor 对象 image 那里建立一个复本,但是这个复本不再是 ClutterTexture 对象,而是 ClutterClone 对象。由于 ClutterClone 也是 ClutterActor 的子类,所以可以使用 ClutterActor 的方法对其进行操作,例如代码中使用了 clutter_actor_set_position() 对其进行了重新定位。
上述程序的运行结果如下图所示。
通过 ClutterClone,你可以复制成千上万的 V 面具,从而建立属于你的 V 字仇杀队,可惜现实中我们似乎没有这样有效的技术。
Cairo 纹理
最后一个演员是 ClutterCairoTexture [11],它是 ClutterTexture 的子类,用于将 Cairo 图形转化为纹理 Actor。这意味着我们可以使用 Cairo 比较强大的 2D 矢量图绘制功能创建 Clutter Actor 对象。看下面的示例:
#include <clutter/clutter.h> static void draw_round_rectangle (cairo_t * cr, double x, double y, double width, double height, double r) { cairo_move_to (cr, x + r, y); cairo_line_to (cr, x + width - r, y); cairo_move_to (cr, x + width, y + r); cairo_line_to (cr, x + width, y + height - r); cairo_move_to (cr, x + width - r, y + height); cairo_line_to (cr, x + r, y + height); cairo_move_to (cr, x, y + height - r); cairo_line_to (cr, x, y + r); cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI / 2.0); cairo_arc (cr, x + width - r, y + r, r, 3 * G_PI / 2, 2 * G_PI); cairo_arc (cr, x + width - r, y + height - r, r, 0, G_PI / 2); cairo_arc (cr, x + r, y + height - r, r, G_PI / 2, G_PI); } int main(int argc, char *argv[]) { if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) return 1; gfloat width = 400, height = 200; ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff }; /* 获取默认的 Stage 并设置其尺寸与颜色 */ ClutterActor *stage = clutter_stage_get_default (); clutter_stage_set_title (CLUTTER_STAGE (stage), "Hello Cairo!"); clutter_actor_set_size (stage, width, height); clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); /* 构建 Cairo 纹理 */ ClutterActor *cairo_texture = clutter_cairo_texture_new (width, height); cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (cairo_texture)); gfloat w, h, x, y, r; x = width / 5.0; y = height / 5.0; w = 3 * width / 5.0; h = 3 * height / 5.0; r = h / 8.0; cairo_set_source_rgb (cr, 0.8, 0.4, 0); cairo_set_line_width (cr, 6); draw_round_rectangle (cr, x, y, w, h, r); cairo_stroke_preserve (cr); cairo_set_source_rgb (cr, 0.8, 0.8, 0.2); cairo_fill (cr); cairo_destroy (cr); clutter_container_add_actor (CLUTTER_CONTAINER (stage), cairo_texture); /* 显示 Stage 及其子 Actor 对象 */ clutter_actor_show_all (stage); /* 开启 Clutter 主循环,响应事件 */ clutter_main (); return 0; }
上面这个示例的代码虽然比前面示例要多一些,但是它的结构却很简单,前提是你需要对 Cairo 绘图有所了解。关键的代码是:
ClutterActor *cairo_texture = clutter_cairo_texture_new (width, height); cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (cairo_texture)); /* 在此处绘制 Cairo 图形 */ ... ... cairo_destroy (cr); clutter_container_add_actor (CLUTTER_CONTAINER (stage), cairo_texture);
其中 clutter_cairo_texture_new() 用于构建一个带有宽度与高度的 Cairo 纹理 Actor; clutter_cairo_texture_create() 从 Cairo 纹理 Actor 对象中获取相关联的 Cairo 渲染环境。一旦有了 Cairo 渲染环境,那么便可以绘制 Cairo 图形了,例如上例绘制的是一个圆角矩形,如下图所示:
待 Cairo 图形绘制完毕,使用 cairo_destroy() 释放 Cairo 渲染环境,无须担心所绘制的图形会因此消失,因为在 cairo_destroy() 运行之时,Clutter 会将 Cairo 图形保存到 Cairo 纹理 Actor 之中。随后使用 clutter_container_add_actor() 将 Cairo 纹理 Actor 添加到 Stage 中即可。
参考文献
[2] 凌乱的舞台
[4] 继承与接口
[5] GObject 对接口的模拟
[6] ClutterText 的文档
[9]『V 字仇杀队』剧照
[10] ClutterClone 的文档
[12] Cairo 项目
转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com