3
votes

Followed is the code referring to very old gtk+1.x FAQ. The purpose is to get the selection of a GtkList. I know GtkList is deprecated and should be replaced with GtkTreeView + GtkListStore. I do know how to use GtkListStore. However, I do want to use GtkList in current situation since GtkListStore is more complex.

The problem for the code below is that it doesn't print anything no matter how many items I select. Please help. My gtk+ version is 2.10.11.

#include <gtk/gtk.h>

void list_changed (GtkList *list, GtkWidget *widget, gpointer user_data)
{
  GList   *items;

  items=GTK_LIST(list)->selection;
  printf("Selected Items: ");
  while (items) 
  {
    if (GTK_IS_LIST_ITEM(items->data))
        printf("%d ", (guint) 
    gtk_object_get_user_data(items->data));
    items=items->next;
  }
  printf("\n");
}

int main(int argc, char *argv[]) 
{
    GtkWidget *window, *list_item, *list;
    guint i;
    gchar *list_items[]={"Item0", "Item1", "foo", "last Item",};
    guint nlist_items=sizeof(list_items)/sizeof(list_items[0]);

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), window);
    gtk_window_set_title(GTK_WINDOW(window), "GtkList");
    gtk_widget_show_all(window);

    list=gtk_list_new();
    gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_MULTIPLE);
    gtk_container_add(GTK_CONTAINER(window), list);
    gtk_widget_show (list);
    g_signal_connect(G_OBJECT(list), "select-child", G_CALLBACK(list_changed), window);

    for (i = 0; i < nlist_items; i++)
    {
      list_item=gtk_list_item_new_with_label(list_items[i]);
      gtk_object_set_user_data(GTK_OBJECT(list_item), (gpointer)i);
      gtk_container_add(GTK_CONTAINER(list), list_item);
      gtk_widget_show(list_item);
    }

    gtk_main();

    return 0;
}
2
GtkList is so deprecated it's not even funny. you should never use it in newly written code.ebassi
also, gtk+ 2.10 is, at this point, more than 8 years old. you won't ever get any bug fixed, or support, by using that kind of release.ebassi

2 Answers

3
votes

instead of using a long since deprecated widget like GtkList, maybe you should detail which problems you have with GtkTreeView and GtkListStore. for instance, creating the tree view and populating it with labels can be achieved using this code (I broke it down for ease of comprehension):

enum {
  COLUMN_TEXT,

  N_COLUMNS
};

static const char *labels[] = {
  "Item 0",
  "Item 1",
  "foo",
  "Last item"
};

GtkTreeModel *
populate_store (void);
{
  GtkListStore *store;
  int i;

  store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING);

  for (i = 0; i < G_N_ELEMENTS (labels); i++)
    {
      gtk_list_store_insert_with_values (store, NULL, i,
                                         COLUMN_TEXT, labels[i],
                                         -1);
    }

  return GTK_TREE_MODEL (store);
}

GtkWidget *
create_tree_view (GtkTreeModel *model)
{
  GtkWidget *widget;

  /* renderer for the column */
  renderer = gtk_cell_renderer_text_new ();

  /* column, to pack renderers and bind them to a column in the model */
  column = gtk_tree_view_column_new_with_attributes ("Items",
                                                     renderer,
                                                     "text", COLUMN_TEXT,
                                                     NULL);

  /* text view, to pack all columns */
  widget = gtk_tree_view_new_with_model (model);
  gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);

  return widget;
}

if you have access to later versions of GTK+, you'd also have better convenience API, but the code above is written using the API as it was available in GTK+ 2.10.

there's a pretty comprehensive tutorial available online at: http://scentric.net/tutorial

if you had access to GTK+ 3.10 you'd also be able to use GtkListBox, which is a simpler widget that allows you to pack multiple widgets in a list; it does not allow multiple selection, and does not scale to multiple thousand items, but for simpler use cases it's probably more appropriate.

my heartfelt suggestion is to

  • start using GtkTreeView
  • update, if at all possible, to a recent version of GTK+
    • and if you could update to GTK+ 3.x it would definitely be better.
0
votes

The problem is this line:

items=GTK_LIST(list)->selection;

GtkList is an opaque struct and you are not supposed to access it: the internal fields are to be considered implementation details and, as you have just discovered, could be bogus data.

From the API doc, it seems there is no way to get the current selection so you must handle it by yourself. The following is an example implementation that also stores the order in which the selection has been performed:

#include <gtk/gtk.h>

static void
dump_items(const GSList *items)
{
    const GSList *item;
    gint n;

    g_print("Selection:");
    for (item = items; item; item = item->next) {
        n = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(item->data), "n"));
        g_print(" %d", n);
    }
    g_print("\n");
}

static void
add_item(GtkList *list, GtkWidget *item, GSList **p_items)
{
    *p_items = g_slist_remove(*p_items, item);
    *p_items = g_slist_append(*p_items, item);
    dump_items(*p_items);
}

static void
remove_item(GtkList *list, GtkWidget *item, GSList **p_items)
{
    *p_items = g_slist_remove(*p_items, item);
    dump_items(*p_items);
}

gint
main(gint argc, gchar *argv[])
{
    GtkWidget *window, *item, *list;
    GSList *items = NULL;
    gchar **p_label, *labels[] = {
        "Item0", "Item1", "foo", "last Item",
        NULL
    };

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_window_set_title(GTK_WINDOW(window), "GtkList");

    list = gtk_list_new();
    gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_MULTIPLE);
    gtk_container_add(GTK_CONTAINER(window), list);
    g_signal_connect(list, "select-child", G_CALLBACK(add_item), &items);
    g_signal_connect(list, "unselect-child", G_CALLBACK(remove_item), &items);

    for (p_label = labels; *p_label; ++p_label) {
      item = gtk_list_item_new_with_label(*p_label);
      g_object_set_data(G_OBJECT(item), "n", GINT_TO_POINTER(p_label - labels));
      gtk_container_add(GTK_CONTAINER(list), item);
    }

    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}