Linux下c語言的圖形編程

簡介

GTK+(GIMP TOOLKIT),是一個跨平臺的圖形界面(GUI)開發工具,是目前LINUX操作系統中較常用的圖形界面開發工具之一,它採用一種非常有特色的面向對象的C語言開發框架(C Framework),應用它可以輕鬆的在LINUX系統平臺的X WINDOW環境下開發出漂亮的圖形界面應用程序。直接用GTK+開發應用程序必須使用C/C++語言,所以您必須具有一定的C語言基礎,最好用C語言開發過應用程序。

GTK+2.0是GNOME2桌面環境的圖形基礎,是GNU工程的一部分,採用LGPL條款分發。於2002年3月正式發佈,目前最穩定的版本是2.0.6 ,最新的2.1.0 版正在開發測試過程中,可以到ftp://ftp.gtk.org/pub/gtk/v2.1下載它的源代碼。


控件的分類

GTK+中的控件實際是用C語言對X WINDOW系統中的控件的簡單封裝,在GTK+中,控件大體上可以分爲兩類,即:

  • 容器控件
  • 非容器控件

非容器控件

GTK+中的非容器控件包括諸如文字標籤、圖像、單行輸入等圖形界面編程中的最基本的元素。下面爲簡單的示例代碼:

GtkWidget *label;
GtkWidget *p_w_picpath;
GtkWidget *entry;
label = gtk_label_new("this is a test label");
/* 創建文字標籤控件 */
p_w_picpath = gtk_p_w_picpath_new_from_file("p_w_picpath.png");
/* 創建圖像控件,指定要顯示的圖像名 */
entry = gtk_entry_new();
/* 創建單行輸入控件 */ 


 

容器控件

在GTK+中,除了非容器控件外,其它多數控件均屬於容器控件,所有容器都是基於GtkContainer對象的,它又分爲兩類:只能容納一個控件的容器和能容納多個控件的容器。

只能容納一個控件的容器

只能容納一個控件的容器是基於GtkBin對象的,其中包括:

  • 窗口類控件(GtkWindow,GtkDialog,GtkMessageDialog,主要是窗口和各種對話框)
  • 滾動窗口(GtkScrolledWindow)
  • 框架類控件(GtkFrame,GtkAspectFrame)
  • 視口(GtkViewport)
  • 各種按鈕(GtkButton,GtkToggleButton)
  • 浮動窗口(GtkHandleBox)
  • 事件盒(GtkEventBox)等

這些控件的特色是隻能容納一個子控件,要想容納多個子控件,必須向其中添加一個能容納多個控件的容器,然後再向此容器中添加控件。

能容納多個控件的容器

能容納多個控件的容器從功能上又可分爲兩種:一種是隻能設定子控件的排放次序,不能設定子控件幾何位置的容器;另一種是可以設定子控件幾何位置的容器。

不能設定子控件幾何位置的容器

只能設定子控件的排放次序、不能設定子控件幾何位置的容器,是GTK+中最常用的容器控件,它包括以下幾類:

  • 只能容納一行或一列子控件的容器--盒狀容器(GtkBox),它又分成兩種橫向盒狀容器(GtkHBox)和縱向盒狀容器(GtkVBox);
  • 盒狀容器的子類--按鈕盒(GtkButtonBox),也分爲橫向按鈕盒(GtkHButtonBox)和縱向按鈕盒(GtkVButtonBox);
  • 能容納多行多列子控件的容器--格狀容器(GtkTable);
  • 能控制子控件的尺寸的容器--分隔面板(GtkPaned),它也分成橫向分隔面板(GtkHPaned)和縱向分隔面板(GtkVPaned);
  • 能分頁顯示多個子控件的容器--多頁顯示控件(GtkNotebook);

此外還包括菜單條、工具條、列表控件等,它們實際上是上述容器控件的靈活運用,本教程不做詳細介紹

可以設定子控件幾何位置的容器

可以設定子控件幾何位置的容器類似於WINDOWS編程中的FORM控件,主要包括兩種:

  • 自由佈局控件(GtkFixed)-- 可以按固定座標放置子控件的容器
  • 佈局控件(GtkLayout)-- 是一個無窮大的滾動區域,可以包含子控件,也可以定製繪圖

以上分類列出了GTK+中各種常用的容器控件的基本情況,含概了GTK+控件大多數的內容。GTK中的容器中又可以包含容器,這樣創建一個複雜的應用程序界面變得非常輕鬆,也使在LINUX下創建圖形界面應用程序不再難做了。


佈局技巧

使用盒狀容器

盒狀容器是在佈局中最常用的一種容器控件,它可以將一系列子控件按順序組織擺放到一個特定的矩形區域內,或一行或一列,子控件有相同的寬度或高度;對於橫向盒狀容器中子控件的高度是一致的,而縱向盒狀容器中的子控件的寬度是一致的。

盒狀容器引入了"排放"這一概念,是指要加入盒狀容器中的子控件順序的起始位置,從前向後還是從後向前,對於橫向盒狀容器來說就是從左到右,對縱向盒狀容器來說就是從上到下,函數gtk_box_pack_start表示從前向後排列子控件,函數gtk_box_pack_end表示從後向前排列子控件,也可以兩者同時使用,在排列時還要設定容器中子控件的間距(以像素爲單位),是否可擴展,是否填充滿整個容器空間等;此外還可以用函數gtk_container_set_border_width來設定容器的邊框寬度。

下面代碼創建了一個簡單的橫向盒狀容器,運行結果如圖所示:

	box = gtk_hbox_new(FALSE,0);
	button1 = gtk_button_new_with_label("按鈕一");
	gtk_box_pack_start(GTK_BOX(box),button1,FALSE,FALSE,3);
	button2 = gtk_button_new_with_label("按鈕二");
	gtk_box_pack_start(GTK_BOX(box),button2,FALSE,FALSE,3);
	button3 = gtk_button_new_with_label("按鈕三");
	gtk_box_pack_start(GTK_BOX(box),button3,TRUE,TRUE,3);
	button4 = gtk_button_new_with_label("按鈕四");
	gtk_box_pack_start(GTK_BOX(box),button4,FALSE,FALSE,3);



圖 1:使用盒狀容器
使用盒狀容器
 

按鈕一、二、四在排列時設定其可擴展屬性爲FALSE,不能隨窗口的改變來改變大小,而按鈕三的可擴展屬性設爲TRUE,則可以改變大小,所以在窗口拉長時按鈕三隨之變長,看到了這樣的效果圖。同樣我們可以用gtk_vbox_new(FALSE,0);函數來創建一個縱向的盒狀容器。

使用按鈕盒

按鈕盒是盒狀容器的子類,所以它具有盒狀容器的所有功能,又具有自己的特點,如可以設定子控件的排列方式等。下面代碼創建了一個簡單的按鈕盒,運行結果如圖所示:

	bbox = gtk_hbutton_box_new();
	gtk_box_set_spacing(GTK_BOX(bbox),5);
	/* 以上代碼設定按鈕盒的子控件間隙 */
	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox),GTK_BUTTONBOX_END);
	/* 以上代碼設定按鈕盒的子控件排列方式 */
	button1 = gtk_button_new_with_label("按");
	gtk_box_pack_start(GTK_BOX(bbox),button1,FALSE,FALSE,0);
	button2 = gtk_button_new_with_label("鈕");
	gtk_box_pack_start(GTK_BOX(bbox),button2,FALSE,FALSE,0);
	button3 = gtk_button_new_with_label("盒");
	gtk_box_pack_start(GTK_BOX(bbox),button3,FALSE,FALSE,0);



圖2:使用按鈕盒
使用按鈕盒
 

與盒狀容器一樣,向按鈕盒中排列按鈕也使用gtk_box_pack_*系列函數,代碼中我們設定按鈕盒中子控件的間距爲5個像素,設定按鈕盒的屬性爲GTK_BUTTONBOX_END,即子控件的對齊方式爲尾對齊(靠橫向的左側或縱向的下部),所以看到這一效果。同樣還可以用gtk_vbutton_box_new函數來創建縱向的按鈕盒。

使用盒狀容器創建帶有圖像和文字的按鈕

按鈕是一種只能容納一個控件的容器,我們這裏加了一個盒狀容器,再向盒狀容器中加圖像和按鈕,從而形成了帶有圖像和文字的按鈕。這正是爲什麼窗口是一種只能容納一個控件的容器,但卻容納了很多控件的原因,其它的此類容器也是如此。下面代碼創建了一個帶圖像和標籤的按鈕(圖像在左面,文字在右面),改動圖像和文字的排放順序,或創建爲後縱向盒狀容器後可以創建另外三種形式的按鈕,效果如圖所示:(看完這段代碼,相信你一定再也不會爲創建帶圖像的按鈕發愁了)

	p_w_picpath = gtk_p_w_picpath_new_from_stock(GTK_STOCK_HELP,GTK_ICON_SIZE_MENU);
	label = gtk_label_new("按鈕標籤");
	box = gtk_hbox_new(FALSE,0);
	gtk_box_pack_start(GTK_BOX(box),p_w_picpath,FALSE,FALSE,2);
	gtk_box_pack_start(GTK_BOX(box),label,FALSE,FALSE,2);
	button = gtk_button_new(); /* 創建按鈕 */
	gtk_container_add(GTK_CONTAINER(button),box);/* 將盒狀容器加入到按鈕中 */



圖 3:使用盒狀容器創建帶有圖像和文字的按鈕
使用盒狀容器創建帶有圖像和文字的按鈕
 

使用滾動窗口

下面代碼創建了一個滾動窗口,並向其中加入了一個帶有三個按鈕的縱向盒狀容器,運行效果如圖所示:

	swin = gtk_scrolled_window_new(NULL,NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
				GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
	vbox = gtk_vbox_new(FALSE,0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox),10);
	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin),vbox);
	button1 = gtk_button_new_with_label("測試按鈕一");
	gtk_box_pack_start(GTK_BOX(vbox),button1,FALSE,FALSE,5);
	button2 = gtk_button_new_with_label("測試按鈕二");
	gtk_box_pack_start(GTK_BOX(vbox),button2,FALSE,FALSE,5);
	button3 = gtk_button_new_with_label("測試按鈕三");
	gtk_box_pack_start(GTK_BOX(vbox),button3,FALSE,FALSE,5);
 



圖 4:使用滾動窗口
使用滾動窗口
 

用函數gtk_scrolled_window_set_policy來設定滾動窗口的滾動方式,即出現橫向滾動條還是出現縱向滾動條,這裏的GTK_POLICY_AUTOMATIC表示自動出現。如果子控件具有滾動屬性,我們還可以用函數gtk_containe_add直接向滾動窗口中加子控件,如常用的文本編輯控件GtkTextView就可以直接加入到滾動窗口中來,其會自動具有滾動條。

使用格狀容器(一)

格狀容器可以容納多行或多列子控件,在創建格狀容器時可以指定格狀容器的行數、列數和子控件是否可以擴展。格狀容器中的子控件可以佔用多個或橫向或縱向的連續的容器空間。格狀容器是採用座標的方式來向其中排放子控件的,左上角爲座標的原點(0,0),所以在向其中排放子控件前一定要設計好子控件的位置,另外它的座標的空間的表示形式是(x1,x2,y1,y2),讀者一定要注意。以下代碼同樣創建了一個3行3列的格狀容器,但我們只向其中排列了三個按鈕,使它們所佔的容器空間各不相同,效果如圖所示:

	table = gtk_table_new(3,3,TRUE);
	button1 = gtk_button_new_with_label("按鈕一");
	gtk_table_attach(GTK_TABLE(table),button1,0,1,0,3,GTK_FILL,GTK_FILL,0,0);
	button2 = gtk_button_new_with_label("按鈕二");
	gtk_table_attach_defaults(GTK_TABLE(table),button2,1,3,0,1);
	button3 = gtk_button_new_with_label("按鈕三");
	gtk_table_attach_defaults(GTK_TABLE(table),button3,1,3,1,3);



圖 5:創建一個 3 行 3 列的格狀容器
創建一個 3 行 3 列的格狀容器
 

使用格狀容器(二)

上面的代碼過於繁瑣,如果子控件只佔用一個容器空間的話,還有更簡單的方法。以下代碼創建了一個3行3列的格狀容器,並均勻的排列了9個按鈕,效果如圖所示:

	table = gtk_table_new(3,3,TRUE);
	for(i=0; i<3; i++)
		for(j=0; j<3; j++)
		{
			buttonx = gtk_button_new_with_label("X");
			gtk_table_attach_defaults(GTK_TABLE(table),buttonx,i,i+1,j,j+1);
		}



圖 6:更簡單的 3 行 3 列的格狀容器
更簡單的 3 行 3 列的格狀容器
 

使用分隔面板

分隔面板只提供了兩個容器空間,也就是說分隔面板中只能容納兩個子控件,分別用函數gtk_paned_add1和gtk_paned_add2來向其中添加子控件,其中第一個空間對應爲橫向分隔面板的左側和縱向分隔面板的上部,另一個則爲第二個容器空間。分隔面板的特色是在容器中有一個分隔條,可以在程序運行時調整子控件的大小,以下代碼創建了三個分隔面板控件將窗口分成了四個區域,我們可以將鼠標放到分隔條上,鼠標型狀改變後按下鼠標隨意改動各子控件的大小,效果如圖所示:

	paned1 = gtk_vpaned_new();
	paned2 = gtk_hpaned_new();
	gtk_paned_add1(GTK_PANED(paned1),paned2);
	button1 = gtk_button_new_with_label("按鈕一");
	gtk_paned_add2(GTK_PANED(paned1),button1);
	button2 = gtk_button_new_with_label("按鈕二");
	gtk_paned_add1(GTK_PANED(paned2),button2);
	paned3 = gtk_vpaned_new();
	gtk_paned_add2(GTK_PANED(paned2),paned3);
	button3 = gtk_button_new_with_label("按鈕三");
	gtk_paned_add1(GTK_PANED(paned3),button3);
	button4 = gtk_button_new_with_label("按鈕四");
	gtk_paned_add2(GTK_PANED(paned3),button4);
 



圖 7:使用分隔面板
使用分隔面板
 

使用多頁顯示

分頁顯示控件在界面中有多個控件要佔用同一容器空間時經常用到,可以用 gtk_notebook_append_page等函數來向分頁顯示控件中添加顯示頁,顯示頁可以是一個單獨的控件,也可以是一個含有多個子控件的容器。以下代碼創建了一個具有三個顯示頁的簡單的分頁顯示佈局,效果如圖所示:

	notebook = gtk_notebook_new();
	label1 = gtk_label_new("這是第一頁\n顯示的內容。");
	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),label1,NULL);
	label2 = gtk_label_new("這是第二頁\n顯示的內容。");
	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),label2,NULL);
	label3 = gtk_label_new("這是第三頁\n顯示的內容。");
	gtk_notebook_append_page(GTK_NOTEBOOK(notebook),label3,NULL);
 



圖 8:使用多頁顯示
使用多頁顯示
 

在GTK+中分顯示控件的功能很強大,如在標題中可以加入圖像,可以滾動顯示,可以顯示右鍵菜單等,在GTK+源代碼的tests目錄中的testgtk.c文件中可以找到它的測試代碼

使用自由佈局

自由佈局控件中可以加入多個子控件,它是用座標的方式來固定要擺放控件的位置,這一點上很類似WINDOWS編程中的FORM控件。下面代碼創建了一個簡單的自由佈局控件,分別向不同位置擺放了三個按鈕,效果如圖所示:

	fixed = gtk_fixed_new();
	gtk_widget_set_usize(fixed,150,150);
	button1 = gtk_button_new_with_label("按鈕一");
	gtk_fixed_put(GTK_FIXED(fixed),button1,5,5);
	button2 = gtk_button_new_with_label("按鈕二");
	gtk_fixed_put(GTK_FIXED(fixed),button2,55,55);
	button3 = gtk_button_new_with_label("按鈕三");
	gtk_fixed_put(GTK_FIXED(fixed),button3,105,105);



圖 9:使用自由佈局
使用自由佈局
 

還可以用函數gtk_fixed_move函數來移動自由佈局容器中的子控件,使之能動態改變子控件的位置。


GtkLayout與GtkFixed的異同

上一節代碼中的GtkFixed改爲GtkLayout後完全可行,並且運行效果也是一樣的,這並不意味GtkLayout與GtkFixed是同一控件,更好的說明是GtkLayout具有GtkFixed 所有功能。它們的區是:

  • GtkLayout具有滾動屬性,理論上可以無限大的,GtkFixed則不具有滾動屬性,並且使用時要設定它的外觀尺寸
  • GtkLayout中的子控件可以定製繪圖,而GtkFixed中的子控件則不可以,從這一點上來講GtkLayout更象一個GtkDrawingArea控件
  • 另外GtkFixed還有很多缺陷,GTK+的開發者們提醒使用者要加以注意


 

參考資料

  • 本教程的所有源代碼可以在 這裏下載。

     
  • 要學習更多的GTK+知識,可以到GTK+網站

     
  • 有關函數說明可見GTK+的API參考手冊

     
  • IBM developerWorks中國網站 Linux 專區 中瀏覽更多的關於 GTK+ 的文章。
     
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章