引文:
一般情况下各个 Actor 在 Stage 中的定位都是硬编码的方式实现的,当 Stage 的尺寸发生变化时,这些 Actor 的位置通常难以进行适应调整。
Clutter 提供了布局管理机制,用来实 现 Actor 的尺寸与位置控制。
正文:
一、Clutter (1.7.4)提供了五种布局方式:
固定布局(ClutterFixedLayout):跟 Actor 硬编码定位没有太多区别,通常不使用它;
单一布局(
ClutterBinLayout):将 Actor 叠放成一摞,通常可用于将多个 Actor 复合在一起;
流布局(
ClutterFlowLayout):当你不知道有多少个 Actor 的时候,并且又想让它们按照水平方向或竖直方向均匀排列,那么就可以使用流布局;
盒子布局(ClutterBoxLayout):将 Actor 单行水平或竖直均匀排列;
表格布局(ClutterTableLayout):将 Actor 按表格的方式均匀排列。
本文只介绍单一布局与流布局,其他布局方式与这两种布局大同小异。
二、 单一布局
可以利用单一布局制作文本框。看下面的示例:
#include <clutter/clutter.h>
int
main(intargc,char*argv[])
{
if(clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return1;
/* Stage 的宽度与高度 */
gfloat w = 400, h = 200;
ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
ClutterColor rect_border_color = { 0xa0, 0x00, 0x00, 0xff };
ClutterColor text_color = { 0xff, 0xe6, 0xe6, 0xff };
/* 获取默认的 Stage 并设置其尺寸与颜色 */
ClutterActor *stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage),"Hello Text Frame!");
clutter_actor_set_size (stage, w, h);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* 构建矩形 Actor */
ClutterActor *rectangle = clutter_rectangle_new_with_color (&stage_color);
clutter_actor_set_size (rectangle, 0.5*w, 0.5*h);
clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 4);
clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle), &rect_border_color);
/* 构建文本 Actor */
ClutterActor *text = clutter_text_new_with_text ("Sans 12",
"中国人指望政府\n"
"美国人指望 X 战警");
clutter_text_set_color (CLUTTER_TEXT (text), &text_color);
clutter_text_set_line_alignment (CLUTTER_TEXT (text), PANGO_ALIGN_CENTER);
/* 构建单一布局 */
ClutterLayoutManager *layout;
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
/* 构建 Box 容器 */
ClutterActor *box = clutter_box_new (layout);
clutter_actor_set_size (box, w, h);
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), rectangle,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), text,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
/* 将 Box 容器添加至 Stage */
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
/* 显示 Stage 及其子对象(矩形 Actor) */
clutter_actor_show_all (stage);
/* 开启 Clutter 主循环,响应事件 */
clutter_main ();
return0;
}
上述代码中,有关矩形与文本 Actor 的构建均在 [1] 中有所讲述。与布局相关的代码如下:
/* 构建单一布局 */
ClutterLayoutManager *layout;
layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
/* 构建 Box 容器 */
ClutterActor *box = clutter_box_new (layout);
clutter_actor_set_size (box, w, h);
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), rectangle,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (layout), text,
CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
/* 将 Box 容器添加至 Stage */
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
Note:布局管理器(ClutterLayoutManager)的实例必须要与一个 Actor 容器(ClutterActor 的子类)实例相结合方可实现 Actor 的布局管理,上例中使用的 Actor 容器是 ClutterBox 容器。
为了实现矩形与文本 Actor 在 Stage 上的居中放置,所以将 Box 容器的尺寸设置与 Stage 相同,然后使用 clutter_bin_layout_add() 向布局管理器中添加矩形与文本 Actor,并将它们在 Box 容器中的布局设为居中(CLUTTER_BIN_ALIGNMENT_CENTER)。
最后将 Box 容器添加到 Stage 中,这样便可在 Stage 中显示文本框的效果,如下图所示。
三、流布局
如果要在 Stage 中将全部的 PDF 页面显示出来,那么建议使用流布局。因为只有流布局可以在一行(或一列)发生溢出时会自动进行换行(或换列)。看下面的示例:
#include <clutter/clutter.h>
#include <poppler/glib/poppler.h>
staticvoid
pdf_page_actor_create (ClutterActor *box, PopplerDocument *doc, gint index)
{
gdouble w, h;
PopplerPage *page = poppler_document_get_page (doc, index);
poppler_page_get_size (page, &w, &h);
ClutterActor *pdf_actor = clutter_cairo_texture_new (w, h);
cairo_t *cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (pdf_actor));
cairo_rectangle (cr, 0, 0, w, h);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_fill (cr);
poppler_page_render (page, cr);
cairo_destroy (cr);
clutter_actor_set_size (pdf_actor, 0.25*w, 0.25*h);
clutter_box_pack (CLUTTER_BOX (box), pdf_actor,
"x-align", CLUTTER_BOX_ALIGNMENT_CENTER,
"y-align", CLUTTER_BOX_ALIGNMENT_CENTER,
"expand", TRUE,
NULL);
}
int
main(intargc,char*argv[])
{
if(clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
return1;
/* Stage 的宽度与高度 */
gfloat w = 640, h = 480;
ClutterColor stage_color = { 0x21, 0x43, 0x5e, 0xff };
PopplerDocument *doc = poppler_document_new_from_file ("file:///your-pdf-file-path", NULL, NULL);
/* 获取默认的 Stage 并设置其尺寸与颜色 */
ClutterActor *stage = clutter_stage_get_default ();
clutter_stage_set_title (CLUTTER_STAGE (stage),"Hello Flow!");
clutter_actor_set_size (stage, w, h);
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
/* 构建流布局 */
ClutterLayoutManager *layout = clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL);
clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout), 8);
clutter_flow_layout_set_column_spacing (CLUTTER_FLOW_LAYOUT (layout), 8);
/* 构建 Box 容器 */
ClutterActor *box = clutter_box_new (layout);
clutter_actor_set_size (box, w, h);
gint total = poppler_document_get_n_pages (doc);
for(gint i = 0; i < total; i++)
pdf_page_actor_create (box, doc, i);
/* 将 Box 容器添加至 Stage */
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
/* 显示 Stage 及其子对象(矩形 Actor) */
clutter_actor_show_all (stage);
/* 开启 Clutter 主循环,响应事件 */
clutter_main ();
return0;
}
该示例只是对 [2] 的示例进行了少许修改,如下:
/* 构建流布局 */
ClutterLayoutManager *layout = clutter_flow_layout_new (CLUTTER_FLOW_HORIZONTAL);
clutter_flow_layout_set_row_spacing (CLUTTER_FLOW_LAYOUT (layout), 8);
clutter_flow_layout_set_column_spacing (CLUTTER_FLOW_LAYOUT (layout), 8);
/* 构建 Box 容器 */
ClutterActor *box = clutter_box_new (layout);
clutter_actor_set_size (box, w, h);
gint total = poppler_document_get_n_pages (doc);
for(gint i = 0; i < total; i++)
pdf_page_actor_create (box, doc, i);
首先构造了流布局管理器(水平方向流),并将它与 Box 容器结合,然后使用 poppler_document_get_n_pages() 获取 PDF 文档的页数,并使用我自定义的 pdf_page_create() 为每幅 PDF 页面建立一份 Cairo 纹理 Actor 并将其添加到 Box 容器中。所得效果如下图所示:
Note:不过流布局在控制行高和列宽方面并非全自动的。对于水平流,只有行高可以自动调整;对于竖直流,只有列宽可以自动调整。因此 Box 容器中的 Actor 的宽、高依然需要程序员自行控制,否则很容易导致 Actor 变形。