Re: treeview question



 Joseph,

 I am not sure if the for loop to free the string is necessary for strings as
strings are strdupped by the model and freed by it when removed. I think you
only need it for gpointer types, and even then calling g_free on a gpointer
might not be what you want (i.e. if gpointer points to a malloc'ed char*, it is
the right way, but not for a , say, struct or pixbuf).


--- "Orgren, Joseph H" <JOSEPH Orgren associates dhs gov> wrote:
Kim,

I started with the "editable_list" demo code and boiled it down to 
something
simpler and more portable.  I also added hooks for error checking.
Maybe this code will be of some use to you:

#include <gtk/gtk.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>


enum { COL_ID, COL_KEY, NUM_COLUMNS };
GtkWidget *main_app_window; // Application's main window.

typedef struct {GCallback edited; GType type; char *label;} COL_PARAMS;


void table_add_item (GtkWidget *button, gpointer data)
{
  GtkTreeIter iter;
  GtkTreeView *treeview = (GtkTreeView *)data;
  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
  GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);

  gtk_list_store_append (GTK_LIST_STORE (model), &iter);
                gtk_tree_selection_select_iter (selection, &iter);
}


void table_remove_item (GtkWidget *button, gpointer data)
{
  GtkTreeIter iter;
  GtkTreeView *treeview = (GtkTreeView *)data;
  GtkTreeModel *model = gtk_tree_view_get_model (treeview);
  GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);

  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
  {
   int index=0, n_columns, i;
        char *path_string;
        gpointer cell_val;

        index = atoi(path_string = gtk_tree_model_get_string_from_iter 
(model, &iter));
   g_free (path_string);

   // Free any data stored dynamically by the model.
   n_columns = gtk_tree_model_get_n_columns (model);
   for (i=0; i<n_columns; i++)
   {
        switch (gtk_tree_model_get_column_type (model, i))
        {
                case G_TYPE_STRING:
                case G_TYPE_POINTER:
                 gtk_tree_model_get (model, &iter, i, &cell_val, -1);
                 g_free (cell_val);
                 break;
        }
   }

   gtk_list_store_remove (GTK_LIST_STORE (model), &iter);

   // Select the row above the deleted row.
   if (gtk_tree_model_get_iter_first (model, &iter)) // Skip if list is 
now empty.
   {
    asprintf(&path_string, "%d", (index ? --index : 0));
    gtk_tree_model_get_iter_from_string (model, &iter, path_string);
    g_free (path_string);
                gtk_tree_selection_select_iter (selection, &iter);
         }
  }
}


GtkTreeView *table_create (int n_columns, COL_PARAMS *cp)
{
  gint i;
  GtkListStore *model;
  GtkTreeView *treeview;
  GtkTreeIter iter;
  GtkCellRenderer *renderer;
  GType *types = malloc (n_columns * sizeof(GType));

  for (i=0; i<n_columns; i++) types[i] = cp[i].type;
  model = gtk_list_store_newv (n_columns, types);
  free(types);
  treeview = (GtkTreeView *)gtk_tree_view_new_with_model ((GtkTreeModel 
*)model);
  for (i=0; i<n_columns; i++)
  {
   renderer = gtk_cell_renderer_text_new ();
   g_signal_connect  (renderer, "edited", cp[i].edited,  model);
   g_object_set_data (G_OBJECT(renderer), "column",   (gpointer)i);
   g_object_set      ((gpointer)renderer, "editable", (gpointer)TRUE, 
NULL);
   gtk_tree_view_insert_column_with_attributes
    (treeview, -1, cp[i].label, renderer, "text", (gpointer)i, NULL);
  }
  return treeview;
}


int key_is_OK (const int id, const char *key)
{
        int retval;
        if (id && key && *key)
        {
         // The next line is totally FAKE!
                retval = 1 & (id ^ (key[strlen(key)-1]));

                if (! retval)
                {
                        // Pop up an error dialog.
   GtkWidget *dialog, *label;
   dialog = gtk_message_dialog_new
    ((GtkWindow *)main_app_window, GTK_DIALOG_DESTROY_WITH_PARENT, 
GTK_MESSAGE_ERROR,
     GTK_BUTTONS_CLOSE, "Invalid ID/Key: %d/%s", id, key);
   gtk_dialog_run (GTK_DIALOG (dialog));
   gtk_widget_destroy (dialog);
                }
        }
        else retval = TRUE;
 return retval;
}


void key_cell_edited
(GtkCellRendererText *cell, const gchar *path_string, const gchar 
*new_text, gpointer data)
{
  GtkTreeModel *model = (GtkTreeModel *)data;
  GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
  GtkTreeIter iter;
  int old_id, new_id, column;
  char *old_key=NULL;

  gtk_tree_model_get_iter (model, &iter, path);
  gtk_tree_model_get (model, &iter, COL_ID, &old_id, COL_KEY, &old_key, 
-1);
  switch (column = (int)g_object_get_data (G_OBJECT (cell), "column"))
  {
   case COL_ID:
    {
        if ((sscanf(new_text, "%d", &new_id)) && key_is_OK (new_id, 
old_key))
                   gtk_list_store_set (GTK_LIST_STORE (model), &iter, 
column, new_id, -1);
    }
    break;
   case COL_KEY:
    {
        if (key_is_OK (old_id, new_text))
        {
         g_free (old_key);
         gtk_list_store_set (GTK_LIST_STORE (model), &iter, column, 
new_text, -1);
        }
    }
    break;
  }
  gtk_tree_path_free (path);
}


gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
{
 gtk_main_quit ();
 return FALSE;
}


int main( int argc, char *argv[] )
{
 GtkWidget *vbox, *hbox, *sw, *treeview, *button;
 GtkTreeModel *model;
 GtkTreeIter iter;
 int i;
 struct { int id;  char *key; } foo[] = {       {999, "ABC123"}, {0,NULL} 
};
 COL_PARAMS col_params[] =
 {
  { G_CALLBACK(key_cell_edited), G_TYPE_INT,    "Tag ID"},
  { G_CALLBACK(key_cell_edited), G_TYPE_STRING, "Key"   }
 };

 /* create window, vbox packing container, scrolled window for table, etc 
*/
 gtk_init (&argc, &argv);
 main_app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 gtk_window_set_title (GTK_WINDOW (main_app_window), "Editable 2");
 g_signal_connect (G_OBJECT (main_app_window), "delete_event", G_CALLBACK 
(delete_event), NULL);
 vbox = gtk_vbox_new (FALSE, 5);
 gtk_container_add (GTK_CONTAINER (main_app_window), vbox);
 gtk_box_pack_start
  (GTK_BOX (vbox), gtk_label_new ("Decryption Keys"), FALSE, FALSE, 0);
 sw = gtk_scrolled_window_new (NULL, NULL);
 gtk_scrolled_window_set_policy
  (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);

 /* create model & view */
 treeview = (GtkWidget *)table_create (NUM_COLUMNS, col_params);

 // Stripe rows (depends on theme)
 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
 
 gtk_tree_selection_set_mode
  (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), 
GTK_SELECTION_SINGLE);

 // Initialize the data in the table.
 model = gtk_tree_view_get_model ((GtkTreeView *)treeview);
 for (i=0; foo[i].id; i++)
 {
  gtk_list_store_append ((GtkListStore *)model, &iter);
  gtk_list_store_set
   ((GtkListStore *)model, &iter, COL_ID, foo[i].id, COL_KEY, foo[i].key, 
-1);
 }

 gtk_container_add (GTK_CONTAINER (sw), treeview);

 /* some buttons */
 hbox = gtk_hbox_new (TRUE, 4);
 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

 button = gtk_button_new_with_label ("Add ID/Key");
 g_signal_connect (button, "clicked",   G_CALLBACK (table_add_item), 
treeview);
 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);

 button = gtk_button_new_with_label ("Remove this ID/Key");
 g_signal_connect (button, "clicked",   G_CALLBACK (table_remove_item), 
treeview);
 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);

 gtk_window_set_default_size (GTK_WINDOW (main_app_window), 400, 300);
 gtk_widget_show_all (main_app_window);
 gtk_main ();
 return 0;
}


Joe Orgren
Senior Engineer
Organizational Strategies Inc.
Supporting the Applied Technology Division/OIT
Bureau of Customs & Border Protection
United States Department of Homeland Security
202-927-3967
202-927-2002

Date: Tue, 05 Aug 2003 21:10:42 +1000
From: kadil <ksadil bigpond com>
Subject: treeview question
To: gtk-app-devel-list gnome org
Reply-To: ksadil bigpond com au

I would like to use a tree-table type widget in my new application. I 
understand that a "Tree View" widget acomplishes this, however it is 
undocumented in the Tutorial and the API is quite "clinical" for a novice 
such as myself. Can someone please direct me to an example  that has more 
has 
a Tree View with more than one column so I can experiment with the API. 

Thanks,
Kim

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list gnome org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list


__________________________________
Do you Yahoo!?
Yahoo! SiteBuilder - Free, easy-to-use web site design software
http://sitebuilder.yahoo.com



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]