1. 程式人生 > >GTK+2.0 中的容器控制元件與佈局技巧

GTK+2.0 中的容器控制元件與佈局技巧

簡介

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 *image;
GtkWidget *entry;
label = gtk_label_new("this is a test label");
/* 建立文字標籤控制元件 */
image = gtk_image_new_from_file("image.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函式來建立縱向的按鈕盒。

使用盒狀容器建立帶有影象和文字的按鈕

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

	image = gtk_image_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),image,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+的開發者們提醒使用者要加以注意