<!-- @page { margin: 2cm } TD P { margin-bottom: 0cm } P { margin-bottom: 0.21cm } -->
1. 如何使用gtk+ 在窗体上绘图
如果要在窗体上绘图,在MFC 中时使用DC 来进行操作的。那么在gtk+ 中是怎么做的呢?
为了捕获构件的时间,我们需要使用事件盒构件。对于绘图程序,我们想知道什么时候鼠标键按下和什么时候鼠标移动,因此我们要用GDK_POINTER_MOTION_MASK 和GDK_BUTTON_PRESS_MASK 。我们也想知道什么时候窗口需要重绘,因此我们也要用GDK_EXPOSURE_MASK 。虽然我们也想在窗口尺寸时得到消息,不过我们不必用GDK_STRUCTURE_MASK 标志,因为所有的窗口都自动设了该标志。
只用GDK_POINTER_MOTION_MASK 是有问题的,这回使服务器在每次用户移动鼠标时向事件队列添加一个移动事件。假设处理一个移动事件需要0.1 秒,但是X 服务器每0.05 秒添加一个新的移动事件。如果用户绘制需要5 秒,那么在释放鼠标键后我们的程序会中断5 秒~ 我们所需要的知识为我们处理的每个时间的获取一个移动事件。解决这个问题的方法是用GDK_POINTER_MOTION_HINT_MASK.
我们用GDK_POINTER_MOTON_MASK 时,在指针进入我们的窗口之后,或者在一个按钮按下或释放事件后,服务器的指针首次移动时向我们发送一个移动事件。后发的移动事件都会被压制,知道我们用如下函数去释放鼠标指针的位置:
GdkWindow* gdk_window_get_pointer (GdkWindow *window,
gint *x,
gint *y,
GdkModifierType *mask);
当我们创建绘图区构件时应该注意,我们完全负责绘制器上边的内容。如果我们的窗口被遮住后曝露出来,我们得到一个爆楼时间,我们必须重绘先前被遮住的部分。在WIN32 API 中是使用WM_PAINT 消息来处理的。那么在GTK+ 中师如何处理的呢?
为了能够正确的重绘,我们必须记住绘制在屏幕上的内容。另外,这显然很麻烦,如果窗口的一部分被清除了,我们需要一步步的重绘。解决的办法是使用一个后端位图。
2. 后端位图
我们用向图像中绘制来代替直接向屏幕绘制,当图像改变或图像的一部分需要显示,我们复制相应的部分到屏幕上。用如下函数创建后端位图:
GdkPixmap* gdk_pixmap_new (GdkWindow *window,
gint width,
gint height,
gint depth);
window 参数设置一个GDK 窗口,位图继承该窗口的所有属性。width 和height 设置位图的大小。depth 设置颜色深度,那是每个像素的二进制位,如果depth 为-1 ,他会自动匹配窗口的颜色深度。
我们在事件“configure_event” 的处理函数中创建位图。这个时间会在我们改变窗口大小时产生,包括窗口创建时。
3. 举例:
/* 绘制区的后端位图 */
static GdkPixmap *pixmap = NULL;
/* 创建一个适当大小的后端位图 */
static gint
configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
if (pixmap)
gdk_pixmap_unref(pixmap);
pixmap = gdk_pixmap_new(widget->window,
widget->allocation.width,
widget->allocation.height,
-1);
gdk_draw_rectangle (pixmap,
widget->style->white_gc,
TRUE,
0, 0,
widget->allocation.width,
widget->allocation.height);
return TRUE;
}
调用函数gdk_draw_ractangle() 清除位图,并初始化为白色。我们暴露时间处理函数处理函数只是简单复制相应部分的位图到屏幕上(用暴露时间的event->area 来确定重绘区域)。
/* 从后端位图重新绘制屏幕 */
static gint
expose_event (GtkWidget *widget, GdkEventExpose *event)
{
gdk_draw_pixmap(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
pixmap,
event->area.x, event->area.y,
event->area.x, event->area.y,
event->area.width, event->area.height);
return FALSE;
}
现在我们来看如何保持屏幕跟随位图的更新,如何在位图上绘制我们需要的东西。GTK 的GDK 库中有许多函数可用于在可绘区域绘图。可绘区域可以使窗口、位图或黑白图,。在上边我们已经看到两个,gdk_draw_rectangle() 和gdk_draw_pixmap() 。
4. 绘图函数
gdk_draw_line ()
gdk_draw_rectangle ()
gdk_draw_arc ()
gdk_draw_polygon ()
gdk_draw_string ()
gdk_draw_text ()
gdk_draw_pixmap ()
gdk_draw_bitmap ()
gdk_draw_image ()
gdk_draw_points ()
gdk_draw_segments ()
5. 图像关联
一个图像关联封装一些信息,如前景色,背景色和线宽。GDK 有一组函数用于创建和修改图像关联,但为了方便,我们仅使用预定义的图像关联。每个构件有一个相关联的风格。其中,存储了去多土相关联。