现在,我们开始向荧幕绘图。我们使用的元件是绘图区元件。一个绘图区元件本质上是一个 X 视窗,没有其它的东西。它是一个空白的画布,我们可以在其上绘制需要的东西。一个绘图区元件用如下函式创建:
GtkWidget* gtk_drawing_area_new (void); |
用如下函式设置元件的预设大小:
void gtk_drawing_area_size (GtkDrawingArea *darea, gint width, gint height); |
当呼叫函式gtk_widget_set_size_request()或用户手动调整包含绘图区的视窗的大小时,预设大小可以无效,这对所有的元件都是一样的。
当我们创建绘图区元件时应该注意,我们完全负责绘制其上的内容。如果我们的视窗被遮住后暴露出来,我们得到一个暴露事件,我们必须重绘先前被遮住的部分。
为了能正确的重绘,我们必须记住绘制在荧幕上的内容。另外,这显然很麻烦,如果视窗的一部分被清除了,我们需一步步的重绘。解决的办法是使用一个幕后的后端位图。我们不直接向荧幕绘制而是绘制影像储存在伺服器的记忆体中但不显示出来,当影像改变或影像的一部分需要显示,我们复制相关的部分到荧幕上。
用如下函式创建后端位图:
GdkPixmap* gdk_pixmap_new (GdkWindow *window, gint width, gint height, gint depth); |
window参数设置一个 GDK 视窗,位图继承该视窗的所有属性。width和height设置位图的大小。depth设置颜色深度,那是每个像素的二进制位数,如果depth设为-1,它会自动匹配视窗的颜色深度。
我们在事件”configure_event”的处理函式中创建位图。这个事件会在我们改变视窗大小时产生,包括视窗创建时。
/* 绘制区的后端位图 */
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_rectangle()清除位图,并初始化为白色。后面我们会详细讲解。
我们的暴露事件处理函式只是简单复制相关部分的位图到荧幕上(用暴露事件的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()。这些函式的完全列表如下:
gdk_draw_point () gdk_draw_line () gdk_draw_rectangle () gdk_draw_arc () gdk_draw_polygon () gdk_draw_pixmap () gdk_draw_bitmap () gdk_draw_image () gdk_draw_points () gdk_draw_segments () gdk_draw_lines () gdk_draw_pixbuf () gdk_draw_glyphs () gdk_draw_layout_line () gdk_draw_layout () gdk_draw_layout_line_with_colors () gdk_draw_layout_with_colors () gdk_draw_glyphs_transformed () gdk_draw_glyphs_trapezoids () |
详见参考文件或标头档<gdk/gdk.h>。这些函式的头两个参数都相同。第一个参数是可绘区域。第二个参数是图形内文 (GC)。
一个图形内文封装一些讯息,如前景色、背景色和线宽。GDK有一组函式用于创建和修改图形内文,但为了方便,我们仅使用预先定义的图形内文。每个元件有一个相关联的风格。(可以在 gtkrc 档案中修改,详见 GTK 的 rc 档案)其中,存储了许多图形内文。一些存取这些图形内文的范例如下:
widget->style->white_gc widget->style->black_gc widget->style->fg_gc[GTK_STATE_NORMAL] widget->style->bg_gc[GTK_WIDGET_STATE(widget)] |
fg_gc、bg_gc、dark_gc和light_gc等栏位是靠一个GtkStateType型别的参数索引取值,该型别可以取如下值:
GTK_STATE_NORMAL, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT, GTK_STATE_SELECTED, GTK_STATE_INSENSITIVE |
例如,GTK_STATE_SELECTED预设的前景色是白色,预设的背景色是暗蓝色。
我们的函式draw_brush()做实际的荧幕绘制工作。函式如下:
/* 在荧幕上绘制一个矩形 */
static void
draw_brush (GtkWidget *widget, gdouble x, gdouble y)
{
GdkRectangle update_rect;
update_rect.x = x - 5;
update_rect.y = y - 5;
update_rect.width = 10;
update_rect.height = 10;
gdk_draw_rectangle (pixmap,
widget->style->black_gc,
TRUE,
update_rect.x, update_rect.y,
update_rect.width, update_rect.height);
gtk_widget_queue_draw_area (widget,
update_rect.x, update_rect.y,
update_rect.width, update_rect.height);
}
|
在位图上绘制了矩形之后,我们呼叫如下函式:
void gtk_widget_queue_draw_area (GtkWidget *widget, gint x, gint y, gint width, gint height) |
注意由x,y,width及height等参数所给定的X区域需要更新,X 会最终会产生一个暴露事件(混合区域需要多次呼叫函式gtk_widget_queue_draw_area()),然后会呼叫暴露事件处理函式,复制相关的部分到荧幕上。
现在我们已经有了一个较完整的绘图程式,只差主视窗部分了。
1 則留言
Comments are closed.