في هذا الجزء من دورة البرمجه في GTK+ , سوف نقوم بتقديم widget جديد يسمي GtkTreeView.
GtkTreeWidget هو Widget معقد يتم استخدامه في عرض واظهار القوائم والاشجار البيانيه. يمكنه ان يحتوي علي عمود او اكثر . ويتعامل بتقنية التصميم (MVC) = (Model View Controller) .هذا يعني ان البيانات منفصله عن العرض view .
هنا بعض الاكائنات الاخري التي تستخدم مع GtkTreeView . ال GtkCellRender يقوم بتحديد كيف ستعرض البيانات في العمود GtkTreeViewColumn . اما بالنسبه ل GtkLisrStore و GtkTreeStore فهم يمثلوا قاعدة البيانات في التصميم اي الي (Model) . يتعاملوا مع البيانات. ويتم اظهارهم في GtrTreeView . المنشأة GtkTreeIter يستخدم في الاشاره الي صف في ال GtkTreeView . والكائن GtkTreeSelection يستخدم يقوم بالتعامل مع الاختيارات .
المثال الاول يعرض قائمه بسيطه. التي يمكنها ان تقوم بعرض بيانات نصيه.
#include <gtk/gtk.h> enum { LIST_ITEM = 0, N_COLUMNS }; static void init_list(GtkWidget *list) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkListStore *store; renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("List Items", renderer, "text", LIST_ITEM, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column); store = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store)); g_object_unref(store); } static void add_to_list(GtkWidget *list, const gchar *str) { GtkListStore *store; GtkTreeIter iter; store = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(list))); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, LIST_ITEM, str, -1); } void on_changed(GtkWidget *widget, gpointer label) { GtkTreeIter iter; GtkTreeModel *model; char *value; if (gtk_tree_selection_get_selected( GTK_TREE_SELECTION(widget), &model, &iter)) { gtk_tree_model_get(model, &iter, LIST_ITEM, &value, -1); gtk_label_set_text(GTK_LABEL(label), value); g_free(value); } } int main (int argc, char *argv[]) { GtkWidget *window; GtkWidget *list; GtkWidget *vbox; GtkWidget *label; GtkTreeSelection *selection; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(window), 10); gtk_widget_set_size_request(window, 270, 250); gtk_window_set_title(GTK_WINDOW(window), "List View"); list = gtk_tree_view_new(); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 5); label = gtk_label_new(""); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5); gtk_container_add(GTK_CONTAINER(window), vbox); init_list(list); add_to_list(list, "Aliens"); add_to_list(list, "Leon"); add_to_list(list, "Capote"); add_to_list(list, "Saving private Ryan"); add_to_list(list, "Der Untergang"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); g_signal_connect(selection, "changed", G_CALLBACK(on_changed), label); g_signal_connect(G_OBJECT (window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main (); return 0; }
في مثالنا , سوف نقوم باظهار خمسة عناصر في ال GtkTreeView . سوف يكون لدينا عمود واحد وسوف نقوم باخافاء الراس الخاص بالعمود (header) .سوف نقوم بوضع صندوق عمودي في النافذه . هذا الصندوف سوف يحتوي علي طفلين GtkTreeView و GtkLabel
list = gtk_tree_view_new(); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
يتم انشاء ال GtkTreeView ويتم اخفاءال headers الخاصه بالعواميد.
label = gtk_label_new(""); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
يتم انشائ ملصق عنواني ويتم محورته ووضعه تحت ال GtkTreeView .
init_list(list);هذه الداله تقوم بتنظيف القائمه ووضع البيانات الخاصه بيها لبدأ العمل علي القائمه.
renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("List Items", renderer, "text", LIST_ITEM, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
بداخل هذه الداله , قمنا بانشاء وربط عمود واحد.
store = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
نقوم بانشاء GtkListStore وكما قلنا من قبل فهذا هو ال (Model) ونقوم بوضعها للقائمه.
g_object_unref(store);ال Model يتم تدميره تلقائيا مع ال view .
add_to_list(list, "Aliens");هذه الداله تقوم بوضع اختيار الي القائمه.
store = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW(list))); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, LIST_ITEM, str, -1);
بادخل الداله add_to_list() , نقوم بالحصول علي ال model باستخدام gtk_tree_view_get_model() . ثم نقوم بربط صف جديد ونقوم بوضع قيمه لهذا الصف والتي هي مرجع من GtrTreeIter وهو كان مختص كما قلنا بتحديد اماكن البيانات.
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));GtkSelectionTree لا تحتاج ان نقوم بانشائها بايدينا . حيث انها يتم انشائها بواسطه GtkTreeView . ولكي تقوم بالحصول علي مرجع من هذا ال widget تستخدم الداله gtk_tree_view_get_selection() .
g_signal_connect(selection, "changed", G_CALLBACK(on_changed), label);
عقب اشارة التغير الصادره من GtkTreeSelection نقوم باستدعاء on_changed() .
gtk_tree_model_get(model, &iter, LIST_ITEM, &value, -1); gtk_label_set_text(GTK_LABEL(label), value);
باداخل الداله , نقوم بالحصول علي قيمة cell في الصف المشار اليه بالكائن iter .
Figure: List View
المثال القدام سوف يقوم بوضع خصائص اخري علي المثال الفائت. سوف نستطيع ان نقوم بحذف واضافة عناصر الي القائمه.
#include <gtk/gtk.h> enum { LIST_ITEM = 0, N_COLUMNS }; GtkWidget *list; static void append_item(GtkWidget *widget, gpointer entry) { GtkListStore *store; GtkTreeIter iter; const char *str = gtk_entry_get_text(entry); store = GTK_LIST_STORE(gtk_tree_view_get_model( GTK_TREE_VIEW(list))); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, LIST_ITEM, str, -1); } static void remove_item(GtkWidget *widget, gpointer selection) { GtkListStore *store; GtkTreeModel *model; GtkTreeIter iter; store = GTK_LIST_STORE(gtk_tree_view_get_model( GTK_TREE_VIEW (list))); model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); if (gtk_tree_model_get_iter_first(model, &iter) == FALSE) return; if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) { gtk_list_store_remove(store, &iter); } } static void remove_all(GtkWidget *widget, gpointer selection) { GtkListStore *store; GtkTreeModel *model; GtkTreeIter iter; store = GTK_LIST_STORE(gtk_tree_view_get_model( GTK_TREE_VIEW (list))); model = gtk_tree_view_get_model (GTK_TREE_VIEW (list)); if (gtk_tree_model_get_iter_first(model, &iter) == FALSE) return; gtk_list_store_clear(store); } static void init_list(GtkWidget *list) { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkListStore *store; renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes("List Item", renderer, "text", LIST_ITEM, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW (list), column); store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW (list), GTK_TREE_MODEL(store)); g_object_unref(store); } int main (int argc, char *argv[]) { GtkWidget *window; GtkWidget *sw; GtkWidget *remove; GtkWidget *add; GtkWidget *removeAll; GtkWidget *entry; GtkWidget *vbox; GtkWidget *hbox; GtkTreeSelection *selection; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); sw = gtk_scrolled_window_new(NULL, NULL); list = gtk_tree_view_new(); gtk_window_set_title (GTK_WINDOW (window), "List View"); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 370, 270); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE); vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 5); hbox = gtk_hbox_new(TRUE, 5); add = gtk_button_new_with_label("Add"); remove = gtk_button_new_with_label("Remove"); removeAll = gtk_button_new_with_label("Remove All"); entry = gtk_entry_new(); gtk_box_pack_start(GTK_BOX(hbox), add, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(hbox), remove, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(hbox), removeAll, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3); gtk_container_add(GTK_CONTAINER (sw), list); gtk_container_add(GTK_CONTAINER (window), vbox); init_list(list); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); g_signal_connect(G_OBJECT(add), "clicked", G_CALLBACK(append_item), entry); g_signal_connect(G_OBJECT(remove), "clicked", G_CALLBACK(remove_item), selection); g_signal_connect(G_OBJECT(removeAll), "clicked", G_CALLBACK(remove_all), selection); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main (); return 0; }
بدلا من ملصق عناوني , قمنا باستخدام ثلاث زراير ومدخل بيانات نصيه واحد.سوف نستطيع ان نقوم باضافة اسماء جديده ديناميكيا ونستطيع ايضا ان نققوم بحذف العنصار المختاره او القائمه كلها.
sw = gtk_scrolled_window_new(NULL, NULL); ... gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); ... gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 5); ... gtk_container_add(GTK_CONTAINER (sw), list);
ال GtkTreeView تم وضعه بداخل نافذه متحركه.
if (gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)) { gtk_list_store_remove(store, &iter); }
الداله gtk_list_store_remove() نقوم بمسح عنصر من القائمه .
gtk_list_store_clear(store);اما هذه الداله فتقوم بمسح كل عناصر القائمه.
if (gtk_tree_model_get_iter_first(model, &iter) == FALSE) return;
هذا الكود يقوم بالتحقق اذا ماكان هناك اي عناتصر باقيه في القائمه .
Figure: Advanced List View
سوف نقوم بساتخدام GtkTreeView لكي نقوم بعرض بيانات متفرعه. في المثالين السابقين قمنا باستخدام List view عارض قائمه , اما الان سوف نستخدم عارض شجري Tree view .
#include <gtk/gtk.h> enum { COLUMN = 0, NUM_COLS } ; void on_changed(GtkWidget *widget, gpointer statusbar) { GtkTreeIter iter; GtkTreeModel *model; char *value; if (gtk_tree_selection_get_selected( GTK_TREE_SELECTION(widget), &model, &iter)) { gtk_tree_model_get(model, &iter, COLUMN, &value, -1); gtk_statusbar_push(GTK_STATUSBAR(statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), value), value); g_free(value); } } static GtkTreeModel * create_and_fill_model (void) { GtkTreeStore *treestore; GtkTreeIter toplevel, child; treestore = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING); gtk_tree_store_append(treestore, &toplevel, NULL); gtk_tree_store_set(treestore, &toplevel, COLUMN, "Scripting languages", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "Python", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "Perl", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "PHP", -1); gtk_tree_store_append(treestore, &toplevel, NULL); gtk_tree_store_set(treestore, &toplevel, COLUMN, "Compiled languages", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "C", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "C++", -1); gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "Java", -1); return GTK_TREE_MODEL(treestore); } static GtkWidget * create_view_and_model (void) { GtkTreeViewColumn *col; GtkCellRenderer *renderer; GtkWidget *view; GtkTreeModel *model; view = gtk_tree_view_new(); col = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(col, "Programming languages"); gtk_tree_view_append_column(GTK_TREE_VIEW(view), col); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(col, renderer, TRUE); gtk_tree_view_column_add_attribute(col, renderer, "text", COLUMN); model = create_and_fill_model(); gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); g_object_unref(model); return view; } int main (int argc, char **argv) { GtkWidget *window; GtkWidget *view; GtkTreeSelection *selection; GtkWidget *vbox; GtkWidget *statusbar; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_title(GTK_WINDOW(window), "Tree View"); gtk_widget_set_size_request (window, 350, 300); vbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(window), vbox); view = create_view_and_model(); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 1); statusbar = gtk_statusbar_new(); gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1); g_signal_connect(selection, "changed", G_CALLBACK(on_changed), statusbar); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_widget_show_all(window); gtk_main(); return 0; }
في مثالنا , قمنا بقسم لغات البرمجه الي قسمين . Scripting & compiling . اقسام اللغات تخدم العقد الرئيسيه (toplevel nodes) لقوائم عناصرها.العقده المختاره حاليا او العنصر يتم اظهاره في شريط الحاله status bar .
الخطوات المتبعه لانشاء الtree مشابهه لتلك المتبعه في انشاء list view .
treestore = gtk_tree_store_new(NUM_COLS, G_TYPE_STRING);
هنا نقوم باستخدام Model مختلف يسمي GtkTreeStore .
gtk_tree_store_append(treestore, &toplevel, NULL); gtk_tree_store_set(treestore, &toplevel, COLUMN, "Scripting languages", -1);
نقوم بعمل GtkTreeStore جديد بعمود واحد.
gtk_tree_store_append(treestore, χld, &toplevel); gtk_tree_store_set(treestore, χld, COLUMN, "Python", -1);
هذا الكود يقوم بعمل عقده toplevel جديده.
Figure: Tree View
Home Contents Top of Page