Cairo 图形指南 (10) —— 文本

本篇讲述如何处理文本。

第一个示例是在 GTK+ 窗口中显示《灵魂伙伴》的部分歌词。

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03.  
04.  
05. static gboolean
06. on_expose_event(GtkWidget *widget,
07.      GdkEventExpose *event,
08.      gpointer data)
09. {
10.    cairo_t *cr;
11.  
12.    cr = gdk_cairo_create(widget->window);
13.  
14.    cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
15.  
16.    cairo_select_font_face(cr, "Purisa" ,
17.        CAIRO_FONT_SLANT_NORMAL,
18.        CAIRO_FONT_WEIGHT_BOLD);
19.  
20.    cairo_set_font_size(cr, 13);
21.  
22.    cairo_move_to(cr, 20, 30);
23.    cairo_show_text(cr, "Most relationships seem so transitory" ); 
24.    cairo_move_to(cr, 20, 60);
25.    cairo_show_text(cr, "They're all good but not the permanent one" );
26.  
27.    cairo_move_to(cr, 20, 120);
28.    cairo_show_text(cr, "Who doesn't long for someone to hold" );
29.  
30.    cairo_move_to(cr, 20, 150);
31.    cairo_show_text(cr, "Who knows how to love you without being told" );
32.    cairo_move_to(cr, 20, 180);
33.    cairo_show_text(cr, "Somebody tell me why I'm on my own" );
34.    cairo_move_to(cr, 20, 210);
35.    cairo_show_text(cr, "If there's a soulmate for everyone" );
36.  
37.    cairo_destroy(cr);
38.  
39.    return FALSE;
40. }
41.  
42.  
43.  
44. int main ( int argc, char *argv[])
45. {
46.    GtkWidget *window;
47.  
48.    gtk_init(&argc, &argv);
49.  
50.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
51.  
52.    g_signal_connect(window, "expose-event" ,
53.        G_CALLBACK(on_expose_event), NULL);
54.    g_signal_connect(window, "destroy" ,
55.        G_CALLBACK(gtk_main_quit), NULL);
56.  
57.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
58.    gtk_window_set_default_size(GTK_WINDOW(window), 420, 250);
59.    gtk_window_set_title(GTK_WINDOW(window), "Soulmate" );
60.    gtk_widget_set_app_paintable(window, TRUE);
61.  
62.    gtk_widget_show_all(window);
63.  
64.    gtk_main();
65.  
66.    return 0;
67. }

在这个示例中,显示了 Natasha Bedingfield 的《灵魂伙伴》的部分歌词。(在这里 ,可以听这首歌,很美妙)

1. cairo_select_font_face(cr, "Purisa" ,
2.     CAIRO_FONT_SLANT_NORMAL,
3.     CAIRO_FONT_WEIGHT_BOLD);

这里设置字体。这个函数接受了三个字体参数的传入,字体的名称、样式与轻重。

1. cairo_set_font_size(cr, 13);

这里设定字号。

1. cairo_move_to(cr, 20, 30);
2. cairo_show_text(cr, "Most relationships seem so transitory" );

 通过在窗口中指定位置并调用 cairo_show_text() 函数显示文本。

 

 

一个字接一个字……

这种效果就是一个字一个字的显示,这些字的绘制存有时间差。

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03.  
04. gpointer text[7] = { "Z" , "e" , "t" , "C" , "o" , "d" , "e" };
05. gboolean timer = TRUE;
06.  
07.  
08. static gboolean
09. on_expose_event(GtkWidget *widget,
10.      GdkEventExpose *event,
11.      gpointer data)
12. {
13.    cairo_t *cr;
14.    cairo_text_extents_t extents;
15.    static gint count = 0;
16.  
17.    cr = gdk_cairo_create(widget->window);
18.  
19.    cairo_select_font_face(cr, "Courier" ,
20.        CAIRO_FONT_SLANT_NORMAL,
21.        CAIRO_FONT_WEIGHT_BOLD);
22.  
23.    cairo_set_font_size(cr, 35); 
24.    cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
25.  
26.    gint i;
27.    gint x = 0;
28.  
29.    for (i = 0; i < count; i++) {
30.        cairo_text_extents(cr, text[i], &extents);
31.        x += extents.width + 2;
32.        cairo_move_to(cr, x + 30, 50);
33.        cairo_show_text(cr, text[i]); 
34.    }
35.  
36.    count++;
37.  
38.    if (count == 8) {
39.        timer = FALSE;
40.        count = 0;
41.    }
42.  
43.    cairo_destroy(cr);
44.  
45.    return FALSE;
46. }
47.  
48. static gboolean
49. time_handler (GtkWidget *widget)
50. {
51.    if (widget->window == NULL) return FALSE;
52.  
53.    if (!timer) return FALSE;
54.  
55.    gtk_widget_queue_draw(widget);
56.    return TRUE;
57. }
58.  
59.  
60. int main ( int argc, char *argv[])
61. {
62.    GtkWidget *window;
63.  
64.    gtk_init(&argc, &argv);
65.  
66.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
67.  
68.    g_signal_connect(window, "expose-event" ,
69.        G_CALLBACK(on_expose_event), NULL);
70.    g_signal_connect(window, "destroy" ,
71.        G_CALLBACK(gtk_main_quit), NULL);
72.  
73.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
74.    gtk_window_set_default_size(GTK_WINDOW(window), 300, 90);
75.    gtk_window_set_title(GTK_WINDOW(window), "ZetCode" );
76.    gtk_widget_set_app_paintable(window, TRUE);
77.  
78.    g_timeout_add(1000, (GSourceFunc) time_handler, (gpointer) window);
79.  
80.    gtk_widget_show_all(window);
81.  
82.  
83.    gtk_main();
84.  
85.    return 0;
86. }

在这个示例中,我们在 GTK+ 窗口中画了“ZetCode”这个字串,并让逐个字母伴随一定的时间差逐一显示。

1. gpointer text[7] = { "Z" , "e" , "t" , "C" , "o" , "d" , "e" };

构造一个字符数组。

1. cairo_select_font_face(cr, "Courier" ,
2.     CAIRO_FONT_SLANT_NORMAL,
3.     CAIRO_FONT_WEIGHT_BOLD);

将字体设置为 Courier。

1. for (i = 0; i < count; i++) {
2.     cairo_text_extents(cr, text[i], &extents);
3.     x += extents.width + 2;
4.     cairo_move_to(cr, x + 30, 50);
5.     cairo_show_text(cr, text[i]); 
6. }

开始逐个字的绘制。extents.width 给出了当前字符的宽度。

 

膨胀

下面这个示例中,我们制造了一种膨胀的效果。这个示例显示了一串在膨胀的居中文本,并且伴有淡出现象。这是很常见的效果,在 flash 动画里经常见到。

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03.  
04.  
05. gpointer text[7] = { "Z" , "e" , "t" , "C" , "o" , "d" , "e" };
06. gboolean timer = TRUE;
07.  
08.  
09. static gboolean
10. on_expose_event(GtkWidget *widget,
11.      GdkEventExpose *event,
12.      gpointer data)
13. {
14.    cairo_t *cr;
15.    cairo_text_extents_t extents;
16.  
17.    static gdouble alpha = 1.0;
18.    static gdouble size = 1;
19.  
20.  
21.    gint x = widget->allocation.width / 2;
22.    gint y = widget->allocation.height / 2;
23.  
24.    cr = gdk_cairo_create(widget->window);
25.  
26.    cairo_set_source_rgb(cr, 0.5, 0, 0);
27.    cairo_paint(cr);
28.  
29.    cairo_select_font_face(cr, "Courier" ,
30.        CAIRO_FONT_SLANT_NORMAL,
31.        CAIRO_FONT_WEIGHT_BOLD);
32.  
33.    size += 0.8;
34.  
35.    if (size > 20) {
36.        alpha -= 0.01;
37.    }
38.  
39.    cairo_set_font_size(cr, size);
40.  
41.    cairo_set_source_rgb(cr, 1, 1, 1);
42.  
43.    cairo_text_extents(cr, "ZetCode" , &extents);
44.    cairo_move_to(cr, x - extents.width/2, y);
45.    cairo_text_path(cr, "ZetCode" );
46.    cairo_clip(cr);
47.    cairo_stroke(cr);
48.    cairo_paint_with_alpha(cr, alpha);
49.  
50.    if (alpha <= 0) {
51.        timer = FALSE;
52.    }
53.  
54.    cairo_destroy(cr);
55.  
56.    return FALSE;
57. }
58.  
59. static gboolean
60. time_handler (GtkWidget *widget)
61. {
62.    if (widget->window == NULL) return FALSE;
63.  
64.    if (!timer) return FALSE;
65.  
66.    gtk_widget_queue_draw(widget);
67.  
68.    return TRUE;
69. }
70.  
71.  
72. int main ( int argc, char *argv[])
73. {
74.    GtkWidget *window;
75.  
76.    gtk_init(&argc, &argv);
77.  
78.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
79.  
80.    g_signal_connect(window, "expose-event" ,
81.        G_CALLBACK(on_expose_event), NULL);
82.    g_signal_connect(window, "destroy" ,
83.        G_CALLBACK(gtk_main_quit), NULL);
84.  
85.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
86.    gtk_window_set_default_size(GTK_WINDOW(window), 350, 200);
87.    gtk_window_set_title(GTK_WINDOW(window), "puff" );
88.    gtk_widget_set_app_paintable(window, TRUE);
89.  
90.    g_timeout_add(14, (GSourceFunc) time_handler, (gpointer) window);
91.  
92.    gtk_widget_show_all(window);
93.  
94.    gtk_main();
95.  
96.    return 0;
97. }

这个示例在 GTK+ 窗口中制造了一种膨胀并且淡出的文本渲染效果。

1. gint x = widget->allocation.width / 2;
2. gint y = widget->allocation.height / 2;

获取窗口中心坐标。

1. cairo_set_source_rgb(cr, 0.5, 0, 0);
2. cairo_paint(cr);

将背景设为暗红色。

1. size += 0.8;

每轮循环,字号都增长 0.8 个单位。

1. if (size > 20) {
2.      alpha -= 0.01;
3. }

当字号大于 20 的时候,就开始淡出。

1. cairo_text_extents(cr, "ZetCode" , &extents);

获取文本尺寸。

1. cairo_move_to(cr, x - extents.width/2, y);

根据文本尺寸来将文本定位在窗口的中心位置。

1. cairo_text_path(cr, "ZetCode" );
2. cairo_clip(cr);

获取文本的的路径,并将其设为当前的裁剪域。

1. cairo_stroke(cr);
2. cairo_paint_with_alpha(cr, alpha);

绘制当前的路径,并为之添加 alpha 值(可实现淡出效果)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值