現在我們知道基本理論了,讓我們來詳細分析helloworld範例程式。
這是按鈕被點擊時要呼叫的回呼函式。在這個範例中我們忽略了參數 widget 和 data,但是使用這些參數也不難。下一個範例會使用 data 參數來告訴我們哪個按鈕被按下了。
static void hello( GtkWidget *widget, gpointer data ) { g_print ("Hello Worldn"); }
接下來的一個回呼函式有點特殊。”delete_event” 在視窗管理員發送這個事件給應用程式時發生。我們在這裡可以選擇對這些事件做什麼。可以忽略它們,可以做一點回應,或是簡單地退出程式。
這個回呼函式傳回的值讓 GTK 知道該如何去做。傳回 TRUE,讓它知道我們不想讓 “destroy” 信號被發出,保持程式繼續執行。傳回 FALSE,我們讓 “destroy” 信號發出,這接著會呼叫 “destroy” 信號處理函式。
static gboolean delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) { g_print ("delete event occurredn"); return TRUE; }
這裡是另一個回呼函式,它通過呼叫 gtk_main_quit() 來退出程式。這個函式告訴 GTK 當控制權返回給它時就從 gtk_main 退出。
static void destroy( GtkWidget *widget, gpointer data ) { gtk_main_quit (); }
我假設你知道 main() 函式…是的,像其它程式一樣,所有的 GTK 程式有一個 main() 函式。
int main( int argc, char *argv[] ) {
接下來宣告兩個指向 GtkWidget 型別的結構指標。它們被用於建構一個視窗和一個按鈕。
GtkWidget *window; GtkWidget *button;
這裡又是 gtk_init()。跟前面一樣,這個初始化工具包,分析命令列裡的參數。它從參數列表中刪除任何可以識別的參數,並且修改 argc 和 argv,使這些被刪除的參數好像從來就不存在一樣,而允許你的程式分析剩餘的參數。
gtk_init (&argc, &argv);
建構一個新視窗,這個很容易。它為 GtkWidget *window 結構分配了記憶體,這樣 window 現在指向了一個有效的結構。它建立了一個新視窗,但是這個視窗直到在程式後面部分我們呼叫 gtk_widget_show(window) 後才會顯示出來。
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
這有兩個連接一個信號處理器到一個物件 (本例中,就是 window ) 的範例。這裡,”delete_event” 和 “destroy” 信號被捕獲。當我們用視窗管理員去關閉視窗或呼叫函式 gtk_widget_destroy() 並將 window 元件作為物件傳給它來銷毀時,”delete_event” 信號發出。當我們在 “delete_event” 信號處理器中傳回 FALSE 值時,”destroy” 信號發出。G_CALLBACK 是巨集,可以為我們執行型別轉換和檢測,同時也增加了程式碼的可讀性。(註:舊版有G_OBJECT已不在範例中使用)
g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), NULL); g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
接下來這個函式用於設置容器物件的屬性。設置視窗邊框寬度為10個像素。在設置元件的屬性這一章還有其它類似函式。
再次,GTK_CONTAINER也是一個執行型別轉換的巨集。
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
這個呼叫建構一個新按鈕。在記憶體中分配空間給一個新的 GtkWidget 結構,初始化它,並使 button 指標指向它。它顯示後上面會有個 “Hello World” 標籤。
button = gtk_button_new_with_label ("Hello World");
在 這,我們讓這個按鈕做一些有用的事。我們給按鈕設置信號處理器,因此當按鈕發出 “clicked” 信號時,hello() 函式被呼叫。我們忽略了 data 參數,簡單地傳送 NULL 給 hello() 回呼函式。很明顯地,當我們用滑鼠點擊按鈕時,信號 “clicked” 被發出。
g_signal_connect (button, "clicked", G_CALLBACK (hello), NULL); 註:下面程式碼為舊版
g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (hello), NULL); |
我 們也要使用這個按鈕退出程式。這將說明 “destroy” 信號怎樣由視窗管理員引發,或由我們的程式引發。當按鈕被點擊(“clicked”)時,和上面一樣,它首先呼叫會 hello() 回呼函式,然後是這個函式,這依賴於它們被設置連接的順序。你可以擁有許多回呼函式,所有的回呼按你設置連接的順序依次執行。因為 gtk_widget_destroy() 函式只接受 GtkWidget *widget 作為唯一的參數,我們這裡用 g_signal_connect_swapped() 函式而不直接使用 g_signal_connect()。
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
註:下面程式碼為舊版
g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), G_OBJECT (window)); |
這是一個封裝呼叫,在封裝元件這一章將作深入講解。不過它相當容易理解。它簡單地告訴 GTK 要把按鈕放在它顯示的視窗裡。注意一個 GTK 容器只能包含一個元件。還有其它的元件,在後面介紹,設計為用來以各種方法佈置多個元件。
gtk_container_add (GTK_CONTAINER (window), button);
一切準備就緒。所有信號處理器連接好了,按鈕也放進了視窗,我們讓 GTK 在螢幕上「顯示」這些元件。視窗元件最後顯示,這樣整個視窗會一下彈出,而不是先見到視窗彈出後再見到按鈕。雖然這個簡單的範例中,你不會注意到。
gtk_widget_show (button); gtk_widget_show (window);
接著,當然,我們呼叫 gtk_main() 函式來等待來自 X 伺服器的事件,當這些事件到來時,呼叫元件發出信號。
gtk_main ();
最後傳回,呼叫函式gtk_main_quit() 後控制權傳回到這裡。
return 0;
現在,當我們用滑鼠點擊一個 GTK 按鈕,元件發出一個 “clicked” 信號。為了讓我們利用這個資訊,程式設置了一個信號處理器來捕獲那個信號,它按我們的選擇依次呼叫函式。在我們的範例中,當按下按鈕時,以 NULL 作為參數呼叫函式 hello(),然後呼叫該信號的下一個處理函式,該函式呼叫 gtk_widget_destroy() 函式,把視窗元件作為參數傳遞給它,銷毀視窗元件。這導致視窗發出 “destroy” 信號,它被捕獲,並且呼叫我們的 destroy() 回呼函式,簡單地退出 GTK。
如果用視窗管理員去關閉視窗,它會引發 “delete_event”。這會呼叫我們的 “delete_event” 處理函式。如果我們在函式中傳回 TRUE,視窗還是留在那裡,什麼事也不發生。傳回 FALSE,會使 GTK 發出 “destroy” 信號,它當然會呼叫 “destroy” 回呼,退出 GTK。
2 則留言