PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : GTK - TreeModel in ComboBox



Rebell
29-10-2005, 14:17
Hallo.

Ich versuche seit Stunden, eine vernünftige Liste in eine GtkComboBox zu stecken, aber es vermag mir einfach nicht gelingen - trotz Beispielcode.

Was ich habe: Eine einfache ComboBox mit Text.
Was ich brauche: Ich benötige sozusagen mehrere Spalten, die ich dann nach belieben verstecken kann.
Wozu ich das brauche: Einfache Einträge in der ComboBox nützen mir nichts, weil ich deren Index nicht bestimmen kann, weil dieser fortlaufend bei 0 anfängt. Möchte ich aber Einträge aus einer Datenbank mit ID und Text in die ComboBox einbauen, benötige ich mehr als einfache Texte.

Schlau wie ich war, habe ich gelesen, dass es dafür GtkTreeModel gibt. Also hab ich gesucht und bin schnell fündig geworden. Das Beispiel funktioniert allerdings nur mit einem TreeView. Versuche ich das (gefüllte) TreeModel einer ComboBox zu übergeben, erscheint zwar der Tree, aber ohne Texte.

Weiß jemand wie das genau funktioniert?

Hier ist mein C-Code, den ich mir zusammengeschustert habe.


#include <gtk/gtk.h>

static GtkTreeModel *
create_and_fill_model (void)
{
GtkListStore *liststore;
GtkTreeIter toplevel, child;

liststore = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);

/* Append an empty top-level row to the tree store.
* Iter will point to the new row */
gtk_list_store_append(liststore, &toplevel);

/* Append another empty top-level row to the tree store.
* Iter will point to the new row */
gtk_list_store_append(liststore, &toplevel);
gtk_list_store_set (liststore, &toplevel,
0, 1,
1, "Hans",
-1);
/* Append a child to the row we just added.
* Child will point to the new row */
gtk_list_store_append(liststore, &toplevel);
gtk_list_store_set (liststore, &toplevel,
0, 2,
1, "Adam",
-1);

return GTK_TREE_MODEL(liststore);
}

static GtkWidget *
create_view (void)
{
GtkTreeViewColumn *col;
GtkWidget *view;
GtkCellRenderer *renderer;

view = gtk_tree_view_new();

/* --- Column #1 --- */

col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col, "ID");

/* pack tree view column into tree view */
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

/* REnderer für erste Spalte */
renderer = gtk_cell_renderer_text_new();

/* pack cell renderer into tree view column */
gtk_tree_view_column_pack_start(col, renderer, TRUE);

/* connect 'text' property of the cell renderer to
* model column that contains the first name */
gtk_tree_view_column_add_attribute(col, renderer, "text", 0);




/* --- Column #2 --- */

col = gtk_tree_view_column_new();

gtk_tree_view_column_set_title(col, "Name");

/* pack tree view column into tree view */
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

gtk_tree_selection_set_mode(gtk_tree_view_get_sele ction(GTK_TREE_VIEW(view)),
GTK_SELECTION_NONE);

return view;
}

int
main (int argc, char **argv)
{
GtkTreeModel *list;
GtkWidget *window, *combo, *view, *vbox;

gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);

vbox = gtk_vbox_new (FALSE, 0);
//gtk_widget_show (vbox);
gtk_container_add (GTK_CONTAINER (window), vbox);

combo = gtk_combo_box_new();
list = create_and_fill_model();
view = create_view();

gtk_tree_view_set_model(GTK_TREE_VIEW(view), list);
g_object_unref(list);
gtk_combo_box_set_model(GTK_COMBO_BOX(combo), list);

gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), view, FALSE, FALSE, 0);
gtk_widget_show_all(window);


gtk_main();

return 0;
}



gcc combotree.c -o combotree `pkg-config gtk+-2.0 --cflags --libs`


Erklärung:
In der ComboBox, sowie im TreeView kommt ein Model aus 2 Spalten (ID, Name) zum Einsatz.
Wobei das TreeModel in Wirklichkeit ein ListStore ist.
Die ComboBox nimmt eigentlich NUR TreeModels an, wenn man es entsprechend castet auch List- bzw. TreeStores. In der GTK-Dokumentation steht, dass man ListStore und TreeStore in Verbindung von TreeView verwenden kann, aber mehr steht dazu nicht. Auch keine Erklärung wie man das in Elementen einbaut, die nur ein TreeModel unterstützen. Da ein TreeModel keine Daten halten kann, sondern nur deren Schnittstelle darstellt.

Im TreeView unter der ComboBox fehlt für die 2te Spalte der Renderer und deshalb wird nur die ID angezeigt. Da in der ComboBox die Einträge zwar enthalten sind aber nicht angezeigt werden, vermute ich dass dort auch ein Renderer rein muss - aber wie?

Rebell
29-10-2005, 20:56
Ich habs hinbekommen:


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

static GtkTreeModel *create_and_fill_model (void)
{
GtkTreeStore *liststore;
GtkTreeIter toplevel, child;

// Erstelle Liste (2 Spalten, Typ Int, Typ String)
liststore = gtk_tree_store_new(2, G_TYPE_UINT, G_TYPE_STRING);

// Erster Eintrag (Wurzel)
gtk_tree_store_append(liststore, &toplevel, NULL);
gtk_tree_store_set (liststore, &toplevel,
0, 1, // Spalte 1, Wert
1, "Hans", // Spalte 2, Wert
-1); // Ende

gtk_tree_store_append(liststore, &toplevel, NULL);
gtk_tree_store_set (liststore, &toplevel,
0, 2,
1, "Adam",
-1);

gtk_tree_store_append(liststore, &toplevel, NULL);
gtk_tree_store_set (liststore, &toplevel,
0, 3,
1, "Eva",
-1);
gtk_tree_store_append(liststore, &child, &toplevel);
gtk_tree_store_set (liststore, &child,
0, 4,
1, "Knut",
-1);
return GTK_TREE_MODEL(liststore);
}

static GtkWidget *create_view (void)
{
GtkTreeViewColumn *col;
GtkWidget *view;
GtkCellRenderer *renderer;

view = gtk_tree_view_new();

/* Erste Spalte */
col = gtk_tree_view_column_new();

// Spaltenkopfbeschriftung
gtk_tree_view_column_set_title(col, "ID");

// An TreeView anhängen
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

/* Renderer für erste Spalte */
renderer = gtk_cell_renderer_text_new();

// Packe Renderer in Spalte
gtk_tree_view_column_pack_start(col, renderer, TRUE);

// Setze Eigenschaft 'text' für Renderer
gtk_tree_view_column_add_attribute(col, renderer, "text", 0);


/* Spalte 2 */
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(col, "Name");
gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);

// -> Hier fehlt der Renderer

// Auswahlmodus des TreeView
gtk_tree_selection_set_mode(gtk_tree_view_get_sele ction(GTK_TREE_VIEW(view)),
GTK_SELECTION_NONE);
return view;
}

static GtkWidget *create_combobox(GtkTreeModel *model) {
GtkWidget *combo = gtk_combo_box_new_with_model(model);
GtkCellLayout *layout;
GtkCellRenderer *renderer;

// Übernehme Zellenlayout
layout = GTK_CELL_LAYOUT (combo);

// Neuer Textrenderer
renderer = gtk_cell_renderer_text_new();

// Weise dem Layout den Textrenderer zu
gtk_cell_layout_pack_start (layout, renderer, FALSE);

// Rendere Spalte 1 als Text, wies aussieht kann ComboBox nur eine Spalte darstellen
gtk_cell_layout_set_attributes (layout, renderer, "text", 1, NULL);

return combo;
}

void
combo_has_changed (GtkComboBox *combo,
gpointer user_data)
{
GtkTreeIter selected;
GtkTreeModel *model;
GValue wert;
unsigned int id;
const gchar *text;

// GValue deinitialisieren (mit 0 füllen)
memset(&wert, 0, sizeof(wert));

// Aktiven Eintrag holen
gtk_combo_box_get_active_iter(combo, &selected);
// TreeModel holen
model = gtk_combo_box_get_model (combo);
// Erste Spalte in GValue speichern
gtk_tree_model_get_value (model, &selected, 0, &wert);
// Hole uint ID
id = g_value_get_uint(&wert);

// Vernichten
g_value_unset(&wert);

// Zweite Spalte in GValue speichern
gtk_tree_model_get_value (model, &selected, 1, &wert);
// Hole string Text
text = g_value_get_string(&wert);
g_print("ID: %d - Text: %s\n", id, text);

// Nochmal vernichten
g_value_unset (&wert);
}

int
main (int argc, char **argv)
{
GtkTreeModel *model;
GtkWidget *window, *view, *vbox, *combo;

gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "delete_event", gtk_main_quit, NULL);

vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);

// Erstelle TreeModel (TreeStore)
model = create_and_fill_model();

// Erstelle ComboBox mit TreeModel
combo = create_combobox(model);

// TreeView
view = create_view();

// Weise Model dem TreeView zu
gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);
g_object_unref(model);

// Aktiviere ersten Eintrag der ComboBox
gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);

// Signal fürs Auswählen
g_signal_connect(combo, "changed", G_CALLBACK(combo_has_changed), NULL);

// In VBox packen
gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), view, FALSE, FALSE, 0);
gtk_widget_show_all(window);


gtk_main();

return 0;
}


Die einfache Listenversion, findet ihr auf Pronix (wo ich die Frage vorher gestellt hatte).
http://www.pronix.de/comment/site-958/open-1249/site-1.html