這一部分講述如何繪制一些簡單的圖元,包括直線、填充與筆畫操作、虛線、線端(Cap)與線的交合等圖形的繪制方法。 直線段 直線段是非?;A的矢量圖形對象。畫一條直線段,需要調用兩個函數:cairo_move_to()
函數,用于設置線段起點;cairo_line_to() 用于設定線段終點。 #include #include double
coordx[100]; double coordy[100]; int count = 0; 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,
0.5); int i, j; for ( i = 0; i 1; i++ ) {
for ( j = 0; j -1; j++ ) {
cairo_move_to(cr, coordx, coordy);
cairo_line_to(cr, coordx[j], coordy[j]); }
} count = 0; cairo_stroke(cr);
cairo_destroy(cr); return FALSE; } gboolean
clicked(GtkWidget *widget, GdkEventButton *event, gpointer
user_data) { if (event->button == 1) {
coordx[count] = event->x; coordy[count++] =
event->y; } if (event->button == 3)
{ gtk_widget_queue_draw(widget); }
return TRUE; } int main (int argc, char
*argv[]) { GtkWidget *window;
gtk_init(&argc, &argv); window =
gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_add_events (window, GDK_BUTTON_PRESS_MASK);
g_signal_connect(window, "expose-event",
G_CALLBACK(on_expose_event), NULL); g_signal_connect(window,
"destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window), "lines");
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_widget_set_app_paintable(window, TRUE);
gtk_widget_show_all(window); gtk_main();
return 0; } 該示例會創建一個支持鼠標交互繪制直線段的 GTK+
窗口。在窗口中使用鼠標左鍵隨便點幾下,每一次點擊時,光標位置的坐標都會被記入長度為 100
的數組;然后點擊鼠標右鍵,所有由鼠標左鍵點擊所得到的點會被彼此連接形成直線段;在窗口中再次點擊鼠標右鍵時,會對窗口繪圖區域進行清除。 下面對該示例程序代碼進行分析:
cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width (cr,
0.5); 設置顏色為黑色,線寬為 0.5pt 為參數,繪制直線段。 int i, j; for ( i =
0; i 1; i++ ) { for ( j = 0; j -1; j++ ) {
cairo_move_to(cr, coordx, coordy);
cairo_line_to(cr, coordx[j], coordy[j]);
} } 用 cairo_move_to() 和 cairo_line_to() 函數在 cr 中定義繪圖路徑 (path),連接
coordx[] 和 coordy[] 所記錄的每個點。
cairo_stroke(cr); cairo_stroke() 函數會將 cr 中的路徑繪制出來。
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL); 設定 button-press-event 事件的回調函數為 clicked ()。
if (event->button == 1) { coordx[count]
= event->x; coordy[count++] = event->y;
} 在 clicked () 函數中,當鼠標左鍵點擊事件發生時,講光標所在位置的 x 和 y 坐標分別記入數組
coordx 和 coordy。 if (event->button == 3) {
gtk_widget_queue_draw(widget); } 在 clicked ()
函數中,當鼠標右鍵單擊時,調用 gtk_widget_queue_draw () 函數重繪窗口區域。
 描繪 (Stroke) 與填充 (Fill) 描繪 (Stroke) 可以繪制形狀的輪廓,填充 (Fill)
則用于向形狀內部灌注顏色。 #include #include #include static
gboolean on_expose_event (GtkWidget * widget,
GdkEventExpose * event, gpointer data) { cairo_t *cr;
cr = gdk_cairo_create (widget->window); int width, height;
gtk_window_get_size (GTK_WINDOW (widget), &width, &height);
cairo_set_line_width (cr, 9); cairo_set_source_rgb (cr, 0.69,
0.19, 0); cairo_arc (cr, width / 2, height / 2,
(width ) / 2 - 10, 0, 2 * M_PI);
cairo_stroke_preserve (cr); cairo_set_source_rgb (cr, 0.3, 0.4,
0.6); cairo_fill (cr); cairo_destroy (cr);
return FALSE; } int main (int argc, char *argv[]) {
GtkWidget *window; gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect
(G_OBJECT (window), "expose-event", G_CALLBACK
(on_expose_event), NULL); g_signal_connect (G_OBJECT (window),
"destroy", G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_position (GTK_WINDOW (window),
GTK_WIN_POS_CENTER); gtk_window_set_default_size (GTK_WINDOW
(window), 200, 150); gtk_widget_set_app_paintable (window,
TRUE); gtk_widget_show_all (window); gtk_main ();
return 0; } 這個示例繪制一個內部填充灰色的圓。 下面對代碼進行解析: #include
之所以引入這個頭文件,是因為程序中使用了圓周率常量 M_PI。 int width, height;
gtk_window_get_size (GTK_WINDOW (widget), &width,
&height); 獲取窗口的寬度與高度尺寸。程序中將使用這些值作為繪制圓形的參考尺寸,以實現窗口尺寸變化時,所繪制的圓的尺寸也會相應變化。
cairo_set_source_rgb (cr, 0.69, 0.19, 0); cairo_arc (cr, width
/ 2, height / 2, (width ) / 2 - 10, 0,
2 * M_PI); cairo_stroke_preserve (cr); 描繪圓的輪廓。這里要注意一下
cairo_stroke_preserve () 函數與 cairo_stroke ()
函數的區別(最好的辦法是用后者替換一下前者,看看程序執行效果)。cairo_stroke_preserve () 函數會將它繪制的路徑依然保存在 cairo
環境中,而 cairo_stroke () 所繪制的路徑,在繪制完成后,就從 cairo的環境中清除了。
cairo_set_source_rgb (cr, 0.3, 0.4, 0.6); cairo_fill (cr); 對使用
cairo_stroke_preserve () 函數繪制的路徑進行藍色填充。
 虛線 (Dash) 每條線都可以用不同的虛線筆 (dash pen) 來畫。虛線模式是通過 cairo_set_dash ()
函數來設定。模式類型通過一個數組來定義,數組中的值均為正數,它們用于設置虛線的虛部分與實部分。數組的長度與偏移量可以在程序中設定。如果數組的長度 為
0,虛線模式就是被禁止了,那所繪制的線是實線。如果數組長度為
1,則對應著虛實均勻分布的虛線模式。偏移量是用來設置在虛線的始端在一個虛線周期(包含一個實部單元和一個虛部單元)內的起始位置。 #include
#include static gboolean on_expose_event (GtkWidget * widget,
GdkEventExpose * event, gpointer data) { cairo_t
*cr; cr = gdk_cairo_create (widget->window);
cairo_set_source_rgba (cr, 0, 0, 0, 1); static const double
dashed1[] = { 4.0, 1.0 }; static int len1 = sizeof (dashed1) / sizeof
(dashed1[0]); static const double dashed2[] = { 4.0, 10.0, 4.0
}; static int len2 = sizeof (dashed2) / sizeof (dashed2[0]);
static const double dashed3[] = { 1.0 }; cairo_set_line_width (cr,
1.5); cairo_set_dash (cr, dashed1, len1, 0); cairo_move_to
(cr, 40, 60); cairo_line_to (cr, 360, 60); cairo_stroke
(cr); cairo_set_dash (cr, dashed2, len2, 10);
cairo_move_to (cr, 40, 120); cairo_line_to (cr, 360, 120);
cairo_stroke (cr); cairo_set_dash (cr, dashed3, 1, 0);
cairo_move_to (cr, 40, 180); cairo_line_to (cr, 360, 180);
cairo_stroke (cr); cairo_destroy (cr); return
FALSE; } int main (int argc, char *argv[]) { GtkWidget
*window; GtkWidget *darea; gtk_init (&argc,
&argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new (); gtk_container_add (GTK_CONTAINER
(window), darea); g_signal_connect (darea, "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect (window, "destroy", G_CALLBACK
(gtk_main_quit), NULL); gtk_window_set_position (GTK_WINDOW
(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_show_all (window); gtk_main (); return
0; } 該示例演示了三種虛線模式的設置及繪制。 下面分析一下關鍵代碼。 static const double
dashed1[] = { 4.0, 1.0 }; 設定第一條虛線的模式,它的實部是 4 個像素,虛部是 1 個像素。 static
int len1 = sizeof (dashed1) / sizeof (dashed1[0]); 計算數組 dashed1 的長度。
cairo_set_dash (cr, dashed1, len1, 0); 設置虛線模式。 darea =
gtk_drawing_area_new (); gtk_container_add (GTK_CONTAINER (window),
darea); 這次,我們是在 drawing_area 部件上繪圖,不再是窗口區域了。
 線帽 (Line caps) 線帽是針對直線段的端點形狀而言的,分為三種:
- CAIRO_LINE_CAP_SQUARE
- CAIRO_LINE_CAP_ROUND
- CAIRO_LINE_CAP_BUTT
對應形狀如下圖所示:
 同一條直線段,CAIRO_LINE_CAP_SQUARE 線帽與 CAIRO_LINE_CAP_BUTT
線帽會導致直線段長度有所差別,前者會比后者長一個線寬尺寸。 #include #include static
gboolean on_expose_event (GtkWidget * widget,
GdkEventExpose * event, gpointer data) { cairo_t *cr;
cr = gdk_cairo_create (widget->window); cairo_set_source_rgba
(cr, 0, 0, 0, 1); cairo_set_line_width (cr, 10);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_move_to (cr,
40, 60); cairo_line_to (cr, 360, 60); cairo_stroke
(cr); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_move_to (cr, 40, 150); cairo_line_to (cr, 360, 150);
cairo_stroke (cr); cairo_set_line_cap (cr,
CAIRO_LINE_CAP_SQUARE); cairo_move_to (cr, 40, 240);
cairo_line_to (cr, 360, 240); cairo_stroke (cr);
cairo_set_line_width (cr, 1.5); cairo_move_to (cr, 40, 40);
cairo_line_to (cr, 40, 260); cairo_stroke (cr);
cairo_move_to (cr, 360, 40); cairo_line_to (cr, 360, 260);
cairo_stroke (cr); cairo_move_to (cr, 365, 40);
cairo_line_to (cr, 365, 260); cairo_stroke (cr);
cairo_destroy (cr); return
FALSE; } 該示例繪制三條具有不同線帽的直線段,同時也展示了不同線帽對線的長度的影響。 下面對關鍵代碼進行簡單分析:
cairo_set_line_width (cr, 10); 設置線的寬度為 10px。 cairo_set_line_cap
(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to (cr, 40, 150);
cairo_line_to (cr, 360, 150); cairo_stroke (cr); 畫了一條線帽為
CAIRO_LINE_CAP_ROUND 的直線段。 cairo_move_to (cr, 40, 40);
cairo_line_to (cr, 40, 260); cairo_stroke
(cr); 這是三條豎線之一,用于表現線帽對線的長度的影響。
 線的交合 (Line joins) 線的交合存在以下三種風格:
- CAIRO_LINE_JOIN_MITER
- CAIRO_LINE_JOIN_BEVEL
- CAIRO_LINE_JOIN_ROUND
對應形狀如下圖所示。
 #include #include 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.1, 0, 0);
cairo_rectangle (cr, 30, 30, 100, 100); cairo_set_line_width (cr,
14); cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
cairo_stroke (cr); cairo_rectangle (cr, 160, 30, 100, 100);
cairo_set_line_width (cr, 14); cairo_set_line_join (cr,
CAIRO_LINE_JOIN_BEVEL); cairo_stroke (cr); cairo_rectangle
(cr, 100, 160, 100, 100); cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); cairo_stroke
(cr); cairo_destroy (cr); return
FALSE; } int main (int argc, char *argv[]) { GtkWidget
*window; GtkWidget *darea; gtk_init (&argc,
&argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new (); gtk_container_add (GTK_CONTAINER
(window), darea); g_signal_connect (darea, "expose-event",
G_CALLBACK (on_expose_event), NULL);
g_signal_connect (window, "destroy", G_CALLBACK
(gtk_main_quit), NULL); gtk_window_set_position (GTK_WINDOW
(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size (GTK_WINDOW (window), 300, 280);
gtk_widget_show_all (window); gtk_main (); return
0; }
該示例采用不同的交合類型繪制了三個矩形。 下面對關鍵代碼進行簡單分析: cairo_rectangle
(cr, 30, 30, 100, 100); cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); cairo_stroke
(cr); 繪制了一個線寬為 14px,交合類型為 CAIRO_LINE_JOIN_MITER 的矩形。

本文來自ChinaUnix博客,如果查看原文請點: |