現在,我們開始向螢幕繪圖。我們使用的元件是繪圖區元件。一個繪圖區元件本質上是一個 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 則留言