網誌存檔

2010年11月16日 星期二

「轉貼」Cairo 圖形指南 (4) —— 基本繪圖

這一部分講述如何繪製一些簡單的圖元,包括直線、填充與筆畫操作、虛線、線端(Cap)與線的交合等圖形的繪製方法。

直線段

直線段是非常基礎的矢量圖形對象。畫一條直線段,需要調用兩個函數: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 <= count - 1; i++ ) {
for ( j = 0; j <= count -1; j++ ) {
cairo_move_to(cr, coordx[i], coordy[i]);
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 <= count - 1; i++ ) {
for ( j = 0; j <= count -1; j++ ) {
cairo_move_to(cr, coordx[i], coordy[i]);
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 < style="color: rgb(102, 204, 102);">) / 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 < style="color: rgb(102, 204, 102);">) / 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 () 函數繪製的路徑進行藍色填充。


沒有留言:

張貼留言