作者:王景 一般一個容器構件只能容納一個構件,如果要在一個容器構件中安排多個子構件,可先將多個子構件放入一個組合框或組合表構件內,再將這個組合框或組合表構件放入該容器構件。 一、如何建立Gtk+應用 1.基本概念 在Linux上開發GUI應用軟件,我們通常利用Gtk+庫。為了深入了解Gtk+的應用,我們首先要明確幾個概念。 (1) 構件(widget)的概念 在Gtk+庫裡的窗口、選單和按鈕等應用實體,我們稱之為構件(widget)。構件具有面向對象的特征,其具體結構由Gtk+庫定義,它對運用構件的程序員來說是透明的,除非你想創建自己的構件。在對構件進行安排時,我們只需要關心構件的處理函數,這樣做的目的就是要對應用程序員屏蔽構件的細節,使程序員將更多的精力集中在應用功能上。 (2) 容器(container)的概念 構件主要分為兩大類,即容器類(container)和雜類(miscellaneous)。大多數構件屬容器類,它們可以像容器一樣容納其它的構件。在安排構件時常常要遵循一個規則:除了組合框(box)和組合表(table)這兩種構件外,其它的容器類構件都只能容納一個構件。雜類構件比容器類構件簡單,但它不能容納其它構件。 (3) 消息及回呼函數的概念 程序必須能對用戶的操作作出反應,在基於GUI的程序設計中,“消息”或“信號”是必要的。用戶點擊選單、各種按鈕、輸入用戶數據、查詢運行結果和拖放,都會產生消息或信號。信號可能需要由軟件來加以處理,這時程序員就需要編寫消息回呼函數。消息或信號的概念類似於Windows中的事件。在Gtk+中經常產生各種信號,用戶產生的大多數信號被忽略,只有程序關心的信號,程序中才有相應的處理函數被調用。程序員要登記信號與處理函數之間的關系,告訴Gtk+哪些信號或事件是程序所關心的。 2. 構件(widget)的運用 在調用Gtk+的構件時,一般進行如下操作步驟: (1) 包含所調用構件的頭文件 頭文件通常存放在/usr/include/gtk/目錄下,該文件裡有對構件的定義及對構件的操作函數,在我們使用構件時,可以經常在這個目錄下查閱構件函數的調用格式或參數。我們不必讓所有構件包含頭文件,因為構件的頭文件已包含在該目錄下一個名為gtk.h的文件裡,包含這個文件就包含了所有構件的頭文件。一般系統將編譯的包含目錄指定為/usr/include,所以我們只需寫明 include 即可。 (2) 聲明構件 聲明構件的過程是為了符合C語言中先聲明後使用的原則。一般在程序開始要聲明構件結構的指針,這就為構件分配了地址。 (3) 構件指針的初始化 調用構件的創建函數,對構件的屬性進行調整(大小、位置和狀態等),接著顯示構件,這一點不能忽略,如果只創建了構件卻忘了顯示(gtk_widget_show),在應用時,用戶就不能看到構件,也就無法對構件進行操作了。 (4) 安排構件的位置與層次關系 構件之間往往是容納與被容納的關系,也就是說容器內還有容器,層層嵌套。要記住一般一個容器構件只能容納一個構件,如果要在一個容器構件中安排多個子構件,可先將多個子構件放入一個組合框或組合表構件內,再將這個組合框或組合表構件放入該容器構件。注意父容器構件要先於子容器構件創建,父容器構件的顯示要在子容器構件的顯示之後。 (5) 編寫事件處理函數 構件的頭文件中定義了構件能響應的事件(消息),但並非所有的消息在應用中都是程序所關心的,對於程序應當響應的事件,程序員要寫出事件處理函數。 二、應用舉例 為了對Gtk+庫的應用有一個具體的認識,讓我們來看一個簡單的應用實例。 1. 初始化Gtk+ 寫Gtk+程序需要調用gtk_init函數對Gtk+庫進行初始化。我們首先將應用程序的變量argc和argv傳遞給gtk_init函數,並檢查主要用於調試的Gtk+選項。如果在變量列表中出現任何這樣的Gtk+參數,就將它移去。在運行gtk_init函數後,它們不應該出現在應用程序中。初始化Gtk+的代碼如下: gtk_init(&&argc,&&argv); 2. 建立構件 首先要建立的構件是窗口,它是應用程序的頂層構件,其它構件一般安排在頂層窗口中。窗口是GUI程序的基本框架,在窗口裡我們可以為用戶安排各種方便的應用。一個應用可以有若干個窗口,這些窗口之間既相互獨立,又有層次的關系。窗口有相對固定的風格,前景色、背景色、字體和字號等,我們應當保持定制的風格,確保不使應用軟件雜亂。 按照上面提出的構件運用步驟,我們創建一個程序主窗口: /?聲明構件指針?/ GtkWidget ?window; /?創建窗口,初始化窗口指針,建立一個頂層窗口?/ window=gtk_window_new(GTK_WINDOW_TOPLEVEL); /?顯示構件?/ gtk_widget_show(window); /?登記消息與消息處理函數的關系?/ gtk_signal_connect(GTK_OBJECT(window),"delete_event",GTK_SIGNAL_FUNC(close_window),NULL); 3. 構件類型的轉換 由於建立的構件是通用構件,需要將它轉換為具體的類型以適合調用更為專用的函數。比如建立按鈕構件函數會返回GtkWidget 指針,但是專用的按鈕子程序要求返回GtkButton指針,所以在調用專用的按鈕函數以前,需要使用GTK_BUTTON宏將通用的GtkWidget指針轉換為GtkButton指針。通常,構件是由其它構件派生的,窗口構件(GtkWindow)是由容器構件GtkContainer派生的,而容器構件是由通用構件派生的。在Gtk+中可以將構件指針轉換為其父類、祖先類構件的任意類型,然後再調用父類或祖先類構件的函數。 4. Gtk+的事件循環 對Gtk+進行初始化並將窗口等構件安排在屏幕上之後,應用軟件需要使用Gtk+開始執行事件的循環函數gtk_main(),沒有這個函數,應用程序運行時就會一閃即逝。但是在調用gtk_main_quit()函數之前對gtk_main()函數的調用並不返回,也就是說只有gtk_main_quit()函數才能停止Gtk+的執行,從而最終退出應用程序。我們把gtk_main_quit()函數放在消息處理函數close_window()之中,這樣,當用戶點擊了窗口的關閉按鈕,Gtk+收到“delelte_event”消息,然後調用close_window(),執行gtk_main_quit()函數,整個程序即可退出。 5. 實例源代碼 現在創建一個顯示“hello”字樣的簡單窗口程序。整個程序實現代碼如下: //hello.c include /?關閉主窗口中的消息處理函數?/ close_window(GtkWidget ?window,gpointer data) { /?中止gtk事件循環?/ gtk_main_quit(); } /?主函數?/ main(int argc,char ?argv) {/?聲明窗口和標簽兩個構件?/ GtkWidget ?window; GtkWidget ?label; /?初始化Gtk+庫?/ gtk_init(&&argc,&&argv); /?初始化window構件?/ window=gtk_window_new(GTK_WINDOW_TOPLEVEL); /?初始化label構件?/ label=gtk_label_new("hello!"); /?將標簽放入窗口內,函數內用GTK_CONTAINER宏將窗口構?/ /?件的指針類型轉換為其父類容器構件的指針類型?/ gtk_container_add(GTK_CONTAINER(window),label); /?顯示label構件?/ gtk_widget_show(label); /?顯示window構件?/ gtk_widget_show(window); /?當窗口獲得'delete_event'消息時調用close_windw函數?/ gtk_signal_connect(GTK_OBJECT(window),"delete_event", GTK_SIGNAL_FUNC(close_window),NULL); /?gtk事件循環?/ gtk_main(); } 6. 編譯源代碼及運行程序 最後談一下Gtk+在程序編譯和運行時有哪些特別之處。在Linux系統下的C編譯器,如gcc,要求編譯時在編譯命令後加上各種參數,如果參數太復雜,最好把命令寫入makefile文件。 前面我們講過在應用程序文件中用到Gtk+函數或定義的每一部分必須包含gtk/gtk.h文件,它是Gtk+的主要包含文件。此外,還必須連接若干庫。Gtk+的開發人員為我們提供了方便。使用gtk-config程序可以簡化這些工作。編譯hello.c源文件成為可執行文件hello的命令如下: gcc hello.c -o hello `gtk-config -cflags``gtk-config -libs` 注意,程序中一定是反引號(在鍵盤上位於字符1的左邊)。`gtk-config`實際運行了gtk-config程序;參數-cflags輸出編譯標志,並將它們插入命令行;參數-libs輸出連接標志並插入命令行。在Gtk+ 1.2以上版本中包含gtk-config程序。在Linux的命令行提示符後敲入`gtk-config -cflags`和`gtk-config -libs`表示給gcc 傳遞參數的正確方法。 用shell命令“chmod -777 hello”將文件hello設定為所有用戶都可執行的文件,再用shell命令“./hello”執行這個文件。 三、小結 本文僅提供了對Gtk+庫應用的基本思路,對於想利用Gtk+開發Linux應用的C程序員來說是入門的一課,深入的應用和開發技巧需要讀者在今後不斷的實踐中獲得。