在 Clutter 场景中显示 PDF 页面
Clutter 的脚本

Clutter 布局管理

Garfileo posted @ 2011年7月19日 10:53 in Clutter 笔记 with tags clutter cairo poppler layout , 4271 阅读

[1] 中的各个 Actor 在 Stage 中的定位都是硬编码的方式实现的,当 Stage 的尺寸发生变化时,这些 Actor 的位置通常难以进行适应调整。Clutter 提供了布局管理机制,用来实现 Actor 的尺寸与位置控制。

Clutter (1.7.4)提供了五种布局方式:

  1. 固定布局(ClutterFixedLayout):跟 Actor 硬编码定位没有太多区别,通常不使用它;
  2. 单一布局(ClutterBinLayout):将 Actor 叠放成一摞,通常可用于将多个 Actor 复合在一起;
  3. 流布局(ClutterFlowLayout):当你不知道有多少个 Actor 的时候,并且又想让它们按照水平方向或竖直方向均匀排列,那么就可以使用流布局;
  4. 盒子布局(ClutterBoxLayout):将 Actor 单行水平或竖直均匀排列;
  5. 表格布局(ClutterTableLayout):将 Actor 按表格的方式均匀排列。

本文只介绍单一布局与流布局,其他布局方式与这两种布局大同小异。

单一布局

可以利用单一布局制作文本框。看下面的示例:

#include <clutter/clutter.h>

int
main(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;

        /* 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 ();
         
        return 0;
}

上述代码中,有关矩形与文本 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);

布局管理器(ClutterLayoutManager)的实例必须要与一个 Actor 容器(ClutterActor 的子类)实例相结合方可实现 Actor 的布局管理,上例中使用的 Actor 容器是 ClutterBox 容器。

为了实现矩形与文本 Actor 在 Stage 上的居中放置,所以将 Box 容器的尺寸设置与 Stage 相同,然后使用 clutter_bin_layout_add() 向布局管理器中添加矩形与文本 Actor,并将它们在 Box 容器中的布局设为居中(CLUTTER_BIN_ALIGNMENT_CENTER)。

最后将 Box 容器添加到 Stage 中,这样便可在 Stage 中显示文本框的效果,如下图所示。

流布局

在 [2] 中谈到了在 Stage 中显示 PDF 页面的基本方法,但是实例中仅显示了三幅 PDF 页面。如果要在 Stage 中将全部的 PDF 页面显示出来,那么建议使用流布局。因为只有流布局可以在一行(或一列)发生溢出时会自动进行换行(或换列)。看下面的示例:

#include <clutter/clutter.h>
#include <poppler/glib/poppler.h>
 
static void
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(int argc, char *argv[])
{
        if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
                return 1;

        /* 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 ();
         
        return 0;
}

该示例只是对 [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 容器中。所得效果如下图所示:

不过流布局在控制行高和列宽方面并非全自动的。对于水平流,只有行高可以自动调整;对于竖直流,只有列宽可以自动调整。因此 Box 容器中的 Actor 的宽、高依然需要程序员自行控制,否则很容易导致 Actor 变形。

参考文献

[1] 五个演员

[2] 在 Clutter 场景中显示 PDF 页面

转载时,希望不要链接文中图片,另外请保留本文原始出处:http://garfileo.is-programmer.com

Avatar_small
pingf 说:
2011年7月21日 16:28

木哈哈....
今天看了下clutter,发现已经把cogl独立出来了....
索性在mingw下编译了下1.7.4
附上链接
http://code.google.com/p/clutter-win32/downloads/list
回头有时间尝试下那个pinpoint能否在win下用....

Avatar_small
Garfileo 说:
2011年7月21日 17:02

@pingf: 嗯,而且 clutter 和 cogl 也快要到 2.0 了。看 wiki 上的信息,貌似 api 变动很多。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter