2

Cairo 初体验

 2 years ago
source link: https://blog.lilydjwg.me/2011/5/13/first-time-to-use-cairo.26721.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

其实我觊觎 Cairo 很久了。昨天看到这篇文章,就下决心试了下。

简单图形的绘制

这个确实很简单,随便从后文的参考资料处抄点代码过来即可:

static gboolean on_expose_event(GtkWidget *widget,
GdkEventExpose *event, gpointer data){
cairo_t *cr;
cr = gdk_cairo_create(widget->window);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width(cr, 1);
cairo_rectangle(cr, 20, 20, 120, 80);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_destroy(cr);
return FALSE;
}

看函数名基本上知道是在做什么了。我需要一个半透明的矩形,于是查文档,找到cairo_set_source_rgba函数即可。那个 cr,我是折腾到最后才明白它代表了绘制的 context (环境/上下文);至于那个cairo_stroke_preserve,我最终弄明白 Cairo 的绘制方法后才明白的。不管是cairo_rectangle还是我后来用到的cairo_arc,都是“画”了一个路径。之所以要把“画”加上引号,是因为路径本身是看不到的。使用cairo_stroke来描绘路径,使用cairo_fill来填充,而后面带_preserve的版本,是说路径处理完了还留着,下一个操作继续用。我之前犯了个错误,把所有的矩形和圆的路径都画好了才绘制,结果矩形和圆之间有道连线,圆的半径也被画出来了。折腾好久才知道应该在每个路径完成后就绘制。

翻了好久的GTK、GDK文档,还是没弄明白该怎么在鼠标拖动时绘制。Google 一下,才看到 Garfileo 的这篇文章,在兴奋之余很有郁闷,Garfileo 以前的 Cairo 相关文章我都收集了,可他为什么后来又换博客了呢。。。。

gtk_widget_add_events(window, GDK_KEY_PRESS_MASK |
GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect(window, "button-press-event",
G_CALLBACK(drawing_start), NULL);
g_signal_connect(window, "button-release-event",
G_CALLBACK(drawing_finish), NULL);
g_signal_connect(GTK_OBJECT(window), "motion_notify_event",
G_CALLBACK(drawing_move), NULL);

就这样就可以了。然后我就开始在每个motion_notify_event发生时画一遍,结果在画的时候图像不停地闪。问了下 gtalk 好友老猫,才知道原来只要在 expose 事件时画就好了,而图像改变后,调用下gtk_widget_queue_draw即可。至于为什么这样图像就不会闪,我至今还不清楚。

我需要在几种不同的选区之间切换。本来用 RadioButton 挺好的,但是我现在只会在 GtkWindow 或者 GtkDialog 里画图。后来就想到了右键菜单。查阅文档后就写出以下代码:

menu = gtk_menu_new();
menu_rect = gtk_menu_item_new_with_label("矩形");
menu_circ = gtk_menu_item_new_with_label("圆形");
menu_poly = gtk_menu_item_new_with_label("多边形");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_rect);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_circ);
/* TODO 绘制多边形 */
/* gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_poly); */
g_signal_connect(menu_rect, "activate",
G_CALLBACK(switch_to_rect), NULL);
g_signal_connect(menu_circ, "activate",
G_CALLBACK(switch_to_circ), NULL);
g_signal_connect(menu_poly, "activate",
G_CALLBACK(switch_to_poly), NULL);
...
}else if(event->button == 3){
gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
}

但是这样点右键时只会显示一个小小的白色小边,就像没有菜单项在里面一样。百思不得其解,于是求助于 Google,最后不知道在哪里看到了,原来还需要对menu调用gtk_widget_show_all。想想也是,对窗口调用gtk_widget_show_all只是把窗口里的东西全部显示出来了,但我这个右键弹出菜单不是在窗口里的呀。

一点题外话

因为要绘制多个图形,本来准备自己写个单链表的,刚写完 node 结构体,突然想到,GLib 里不是有各种数据结构吗?于是再查文档,找到 GSList,愉快地用上了。g_slist_foreach这个函数非常好用。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK