GTK+ 示例/樹形檢視/可編輯單元格
使用 GtkCellRendererText,您不僅可以顯示文字,還可以透過雙擊單元格允許使用者直接在樹形檢視中編輯單個單元格的文字。
要使此功能正常工作,您需要告訴單元格渲染器該單元格是可編輯的,您可以透過將相關文字單元格渲染器的 "editable" 屬性設定為 TRUE 來實現。您可以根據每行設定(允許您將每個單獨的單元格設定為可編輯或不可編輯),透過屬性將 "editable" 屬性連線到樹模型中的布林型別列;或者,您可以簡單地...
g_object_set(renderer, "editable", TRUE, NULL);
...在建立渲染器時,這會將該特定渲染器列中的所有行設定為可編輯。
現在我們的單元格是可編輯的,我們也希望在單元格被編輯時收到通知。這可以透過連線到單元格渲染器的 "edited" 訊號來實現
g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, NULL);
每當單元格被編輯時,就會呼叫此回撥。我們可以傳遞一個指向模型的指標作為使用者資料以方便起見,而不是傳遞 NULL,因為我們可能希望將新值儲存在模型中。
"edited" 訊號的回撥看起來像這樣(API 參考在這個特定情況下有點缺乏)
void cell_edited_callback (GtkCellRendererText *cell,
gchar *path_string,
gchar *new_text,
gpointer user_data);
樹路徑以字串形式傳遞到 "edited" 訊號回撥。您可以使用 gtk_tree_path_new_from_string 將其轉換為 GtkTreePath,或使用 gtk_tree_model_get_iter_from_string 將其轉換為迭代器。
請注意,單元格渲染器不會為您更改儲存中的資料。在單元格被編輯後,您只會收到 "edited" 訊號。如果您不更改儲存中的資料,舊文字將再次呈現,就好像什麼也沒發生一樣。
如果您有多個(渲染器)列包含可編輯單元格,則無需為每個渲染器提供不同的回撥,您可以對所有渲染器使用相同的回撥,並將一些資料附加到每個渲染器,以便您以後在回撥中檢索這些資料以瞭解哪個渲染器/列已被編輯。例如,這樣做
renderer = gtk_cell_renderer_text_new();
...
g_object_set_data(G_OBJECT(renderer), "my_column_num", GUINT_TO_POINTER(COLUMN_NAME));
...
renderer = gtk_cell_renderer_text_new();
...
g_object_set_data(G_OBJECT(renderer), "my_column_num", GUINT_TO_POINTER(COLUMN_YEAR_OF_BIRTH));
...
其中 COLUMN_NAME 和 COLUMN_YEAR_OF_BIRTH 是列舉值。然後,您可以在回撥中使用以下方法獲取列號
guint column_number = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(renderer), "my_column_num"));
您可以使用此機制將各種自定義資料附加到任何物件或小部件,並使用您喜歡的字串識別符號。
gtk-demo 中有一個可編輯單元格的良好示例,它是 Gtk+ 原始碼樹的一部分(位於 gtk+-2.x.y/demos/gtk-demo)。
您可以使用 gtk_tree_view_set_cursor(或者如果您在同一個樹形檢視列中打包了多個可編輯單元格渲染器,則使用 gtk_tree_view_set_cursor_on_cell)將游標移動到樹形檢視中的特定單元格,並且如果您想開始編輯該單元格。同樣,您可以使用 gtk_tree_view_get_cursor 獲取當前行和焦點列。使用 gtk_widget_grab_focus(treeview) 將確保樹形檢視具有鍵盤焦點。
正如 API 參考中指出的,樹形檢視需要被實現才能進行單元格編輯。換句話說:如果您想在程式啟動時立即開始編輯特定單元格,您需要使用 g_idle_add 設定一個空閒超時,以便在視窗和其他所有內容都實現後立即執行此操作(在超時中返回 FALSE 以使其只執行一次)。或者,您可以使用 g_signal_connect_after 連線到樹形檢視的 "realize" 訊號以實現相同的效果。
連線到樹形檢視的 "cursor-changed" 和/或 "move-cursor" 訊號以跟蹤游標的當前位置。
就像您可以設定 GtkCellRendererText 可編輯一樣,您可以透過設定 "activatable" 屬性來指定 GtkCellRendererToggle 是否應該在被點選時更改其狀態 - 可以在建立渲染器時(在這種情況下,該列中的所有單元格都可點選)或透過屬性將渲染器屬性連線到模型的布林型別列來實現。
連線到切換單元格渲染器的 "toggled" 訊號,以便在使用者點選切換按鈕(或單選按鈕)時收到通知。使用者點選不會更改儲存中的值,也不會更改渲染的值的外觀。切換按鈕只有在您更新儲存中的值時才會更改狀態。在此之前,它將處於 "不一致" 狀態,這也是您應該從模型而不是從單元格渲染器中讀取該單元格的當前值的原因。
"toggled" 訊號的回撥看起來像這樣(API 參考在這個特定情況下有點缺乏)
void cell_toggled_callback (GtkCellRendererToggle *cell,
gchar *path_string,
gpointer user_data);
就像文字單元格渲染器的 "edited" 訊號一樣,樹路徑以字串形式傳遞到 "toggled" 訊號回撥。您可以使用 gtk_tree_path_new_from_string 將其轉換為 GtkTreePath,或使用 gtk_tree_model_get_iter_from_string 將其轉換為迭代器。
儘管 GtkSpinButton 實現了 GtkCellEditable 介面(就像 GtkEntry 一樣),但沒有簡單的方法可以獲得在編輯模式下使用旋轉按鈕而不是普通條目 的單元格渲染器。
要獲得此功能,您需要編寫一個新的單元格渲染器,其工作原理與 GtkCellRendererText 非常相似,或者您需要編寫一個新的單元格渲染器類,該類派生自文字單元格渲染器,並在編輯模式下更改行為。
最乾淨的解決方案可能是編寫一個 'CellRendererNumeric',它執行文字單元格渲染器執行的所有操作,只是它有一個浮點型別屬性,而不是 "text" 屬性,還有一個額外的位數屬性。但是,似乎還沒有人這樣做,因此您需要自己編寫一個,或者找到另一種方法來在編輯模式下獲得旋轉按鈕。
在本教程的程式碼示例中,有一個基於 GtkCellRendererText 的 CellRendererSpin 偽造實現,它在編輯模式下顯示旋轉按鈕。但是,該實現不是很好,因此您需要確保它在您的特定環境中有效,並在需要時對其進行修改。