在GTK+的所有構(gòu)件(widget)中,GtkTreeView算是比較難的一個(gè)了,做一個(gè)完整的GtkTreeView要牽涉到不少其他的構(gòu)件或?qū)ο螅瑢?duì)于初次使用GtkTreeView的朋友來(lái)說(shuō),可能有點(diǎn)難度,因此我就我所知道的結(jié)合GTK+ API手冊(cè)來(lái)給初來(lái)乍到的朋友略講一下。希望對(duì)正在使用Gtk+的朋友有所幫助。
你可以在這里下載源代碼。
這是測(cè)試程序執(zhí)行的界面。

下面我們就來(lái)講解如何使用GtkTreeView構(gòu)件
一、MVC
首先應(yīng)該介紹的是MVC這個(gè)模式,Model/View/Controller(模式/視圖/控制器),GtkTreeView就是按照這樣的結(jié)構(gòu)來(lái)設(shè)計(jì)的。這樣的好處是,讓數(shù)據(jù)和視圖進(jìn)行分離,同一份數(shù)據(jù)可以設(shè)計(jì)不同的視圖來(lái)顯示。如同一份數(shù)據(jù),我可以在一個(gè)界面中用條狀圖來(lái)顯示,同時(shí)又可以用曲線來(lái)顯示。當(dāng)你更新你的數(shù)據(jù)的時(shí)候,視圖就會(huì)自動(dòng)更新來(lái)顯示你的數(shù)據(jù)變化,所以這部分工作就是控制器來(lái)完成的了。之所以要講MVC設(shè)計(jì)模式的原因就是,我們的GtkTreeView構(gòu)件就是這么來(lái)設(shè)計(jì)的。所以先了解了這個(gè)再來(lái)學(xué)GtkTreeView,理解就容易多了。
二、GtkTreeView的組成
上面我都說(shuō)了,要使用GtkTreeView要牽涉到其他不少的構(gòu)件或?qū)ο?,因此下面我們就?lái)看一下在使用GtkTreeView時(shí)我們一共需要哪些構(gòu)件或?qū)ο蟆?/font>
1,GtkTreeView -- 樹(shù)視圖
2,GtkTreeViewColumn -- 列視圖
3,GtkCellRenderer -- 渲染器
4,GtkTreeModel -- 樹(shù)模式(樹(shù)狀or鏈表)
三、創(chuàng)建一個(gè)樹(shù)視圖
3.1 第一步:創(chuàng)建一個(gè)模式
Gtk+提供了兩種簡(jiǎn)單的模式,一個(gè)是GtkListStore,一個(gè)是GtkTreeStore。如果你對(duì)模式理解還有一些困難的話,其實(shí)我們完全可以簡(jiǎn)單的將GtkListStore和GtkTreeStore理解成數(shù)據(jù)庫(kù),它們就是存放我們數(shù)據(jù)的地方。一個(gè)是存放鏈?zhǔn)降臄?shù)據(jù),一個(gè)是存放樹(shù)狀的數(shù)據(jù)。我們可以通過(guò)下面的函數(shù)來(lái)創(chuàng)建一個(gè)模式(數(shù)據(jù)庫(kù));
GtkListStore *store;
store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
這個(gè)函數(shù)創(chuàng)建一個(gè)了一個(gè)鏈?zhǔn)降哪J?,這個(gè)鏈表具有兩列。它們分別具有字符串類型和布爾類型,典型的用法我們是不會(huì)直接使用2來(lái)標(biāo)明這個(gè)鏈表的列數(shù)的。我們根據(jù)Gtk+api手冊(cè)提供的方法,創(chuàng)建一個(gè)模式更好的方法是按照下面的方式來(lái)創(chuàng)建:
enum{
MYID_COLUMN,
TITLE_COLUMN,
AUTHOR_COLUMN,
STATUS_COLUNM,
NBR_COLUMNS
};
store = gtk_list_store_new(NBR_COLUMNS, /* NBR_COLUMNS = 4 */
G_TYPE_INT,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_FLOAT);
3.1 第二步:向模式(數(shù)據(jù)庫(kù))中添加數(shù)據(jù)
當(dāng)我們創(chuàng)建好了我們的模式之后,我們就可以向其中添加數(shù)據(jù)了,我們可以通過(guò)下面的函數(shù)和方法來(lái)向我們的模式中添加數(shù)據(jù):
GtkTreeIter iter; /* 迭代器 */
gtk_tree_store_append(store, &iter, NULL); /* 獲取插入的位置 */
gtk_tree_store_set(store, &iter,
MYID_COLUMN, 1,
TITLE_COLUMN, "美麗的大草原",
AUTHOR_COLUMN, "甲A",
-1);
注意:最后一個(gè)參數(shù)是-1,因?yàn)?/font>gtk_tree_store_set()這個(gè)函數(shù)是一個(gè)變參數(shù)函數(shù),也就是說(shuō)參數(shù)的個(gè)數(shù)可以改變的,因此需要一個(gè)-1來(lái)標(biāo)志參數(shù)的結(jié)束。通過(guò)上面的語(yǔ)句我們就向模式中添加了一行數(shù)據(jù)了??赡苣銜?huì)問(wèn)iter是做什么的,從字面以上我們可以讀成“迭代器”,也正如它的意思(其實(shí)我們不用管那么多),不用知道GtkTreeIter內(nèi)部結(jié)構(gòu)是怎么樣的,我們只需把它看作用來(lái)標(biāo)志store的某一行的一個(gè)數(shù)據(jù)就可以了。通過(guò)gtk_tree_store_append這個(gè)函數(shù),我們就得到了我們下一個(gè)可以插入數(shù)據(jù)的位置是什么了,iter就標(biāo)志了這個(gè)位置。我們還可以繼續(xù)通過(guò)這兩個(gè)函數(shù),不斷的望模式中添加數(shù)據(jù)。在gtk_tree_store_append的第三個(gè)參數(shù)為NULL表示獲取頂層的迭代器iter.我們也可以獲取某一迭代器的迭代器。如:
gtk_tree_store_append (store, &iter1, NULL); /* 獲取頂層的迭代器iter */
gtk_tree_store_set (store, &iter1,
TITLE_COLUMN, "我的分類1",
AUTHOR_COLUMN, "",
CHECKED_COLUMN, FALSE,
-1);
gtk_tree_store_append (store, &iter2, &iter1); /* 獲取子迭代器 */
gtk_tree_store_set (store, &iter2,
TITLE_COLUMN, "我的標(biāo)題1",
-1);
gtk_tree_store_append (store, &iter2, &iter1);
gtk_tree_store_set (store, &iter2,
TITLE_COLUMN, "我的標(biāo)題2",
-1);
...
這里我就沒(méi)有編寫(xiě)子iter用法的列子了。關(guān)心的同學(xué)可以自己去查閱GTK+API手冊(cè),經(jīng)過(guò)上面的講解應(yīng)該不難了
3.2 創(chuàng)建一個(gè)視圖
當(dāng)我們創(chuàng)建完成我們的模式(數(shù)據(jù)庫(kù))創(chuàng)建之后,我們就可以創(chuàng)建一個(gè)視圖來(lái)顯示它了。這就要用到我們的GtkTreeView視圖了。
GtkWidget* tree;
tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
然后我們定義這個(gè)視圖的列,我們需要用到一個(gè) GtkTreeViewColumn 的對(duì)象了
GtkCellRenderer *renderer;/* 渲染器 */
GtkTreeViewColumn *column;
renderer = gtk_cell_renderer_text_new();
g_object_set(G_OBJECT(renderer), "foreground", "red", NULL);
column = gtk_tree_view_column_new_with_attributes("編號(hào)",
renderer,
"text", AUTHOR_COLUMN,
NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
上面的幾條語(yǔ)句就定義了一個(gè)列對(duì)象了,并且把這個(gè)列對(duì)象與模式的第MYID_COLUMN列聯(lián)系起來(lái)了,然后我們將這個(gè)列添加到我們的tree視圖中。按照同樣的方式我們就可以添加其他更多的列了。
到了這一步我們也算了解了GtkTreeView的創(chuàng)建的過(guò)程了,最后我們?cè)贋槊總€(gè)行添加一個(gè)行選擇信號(hào)處理函數(shù)就比較完美了。
3.3 添加行選擇信號(hào)
大多數(shù)的應(yīng)用程序不僅僅只需要處理顯示數(shù)據(jù)就完成了,而且還需要獲取用戶的輸入信號(hào),為了達(dá)到這個(gè)目的,我們使用"changed"信號(hào)來(lái)與用戶的選擇信號(hào)進(jìn)行關(guān)聯(lián)起來(lái)。
/* changed信號(hào)處理函數(shù)原型 */
static void tree_selection_changed(GtkTreeSelection *selection, gpointer data);
/* 設(shè)置選擇對(duì)象*/
GtkTreeSelection *select;
select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
g_signal_connect(G_OBJECT(select), "changed",
G_CALLBACK(tree_selection_changed),
NULL);

三、總結(jié)
為了給上面的講解有一個(gè)更加直觀的了解,我為其寫(xiě)了一個(gè)簡(jiǎn)單的用例,在這個(gè)用例中,我設(shè)計(jì)了4列其他們之間完全沒(méi)有任何的聯(lián)系,只是為了給大家演示某種對(duì)象或控件的用法,例如我把"編號(hào)"列的字體設(shè)為了紅色,是為了讓大家了解“渲染器”的用法,給程序添加一個(gè)進(jìn)度條,是為了給大家演示在GtkTreeView中進(jìn)度條,該怎么使用,只要在加上一個(gè)計(jì)時(shí)器,進(jìn)度條就可以動(dòng)起來(lái)了。希望這篇文章對(duì)各位學(xué)習(xí)GtkTreeView的同學(xué)有所幫助,由于代碼有點(diǎn)長(zhǎng)度,因此沒(méi)有列在文章中,但是在文章的開(kāi)頭我已經(jīng)提供了下載源代碼的連接。其中包含一個(gè)GtkTreeView.c的文件,和Makefile文件,以及一個(gè)已經(jīng)編譯過(guò)的可直接運(yùn)行的GtkTreeView程
序,如果點(diǎn)擊不能運(yùn)行,請(qǐng)修改該程序的屬性以允許該程序執(zhí)行。
代碼預(yù)覽:

注意:如果你要親自編譯,請(qǐng)確保你已經(jīng)安裝了Gtk庫(kù)文件,安裝方法sudo apt-get install libgtk+-2.0。如果安裝不了,請(qǐng)換一個(gè)更新源。有什么問(wèn)題可以給我留言,如果你無(wú)法下載源代碼,請(qǐng)留下你的郵箱,我將直接發(fā)送到你的郵箱里面去。