Home  Contents

GtkTreeView Widget

في هذا الجزء من دورة البرمجه في GTK+ , سوف نقوم بتقديم widget جديد يسمي GtkTreeView.

GtkTreeWidget هو Widget معقد يتم استخدامه في عرض واظهار القوائم والاشجار البيانيه. يمكنه ان يحتوي علي عمود او اكثر . ويتعامل بتقنية التصميم  (MVC) = (Model View Controller) .هذا يعني ان البيانات منفصله عن العرض view .

هنا بعض الاكائنات الاخري التي تستخدم مع GtkTreeView . ال GtkCellRender يقوم بتحديد كيف ستعرض البيانات في العمود GtkTreeViewColumn . اما بالنسبه ل GtkLisrStore و GtkTreeStore فهم يمثلوا قاعدة البيانات في التصميم اي الي (Model) . يتعاملوا مع البيانات. ويتم اظهارهم في GtrTreeView . المنشأة GtkTreeIter يستخدم في الاشاره الي صف  في ال GtkTreeView . والكائن GtkTreeSelection  يستخدم  يقوم بالتعامل مع الاختيارات .



Simple List View

المثال الاول يعرض قائمه بسيطه. التي يمكنها ان تقوم بعرض بيانات نصيه.

#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 .


List View

Figure: List View



Advanced 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;

هذا الكود يقوم بالتحقق اذا ماكان هناك اي عناتصر باقيه في القائمه .


Advanced List View

Figure: Advanced List View



Tree 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 جديده.


Tree View

Figure: Tree View




Home ‡ Contents ‡ Top of Page