cgtk3gnomegnome-3gnome-builder

Creating a list of widgets in Gtk using C


I want to create a window in Gtk that looks something like this. widgets in glade

The left pane in the top window has a button labelled "Add to list". I have configured the callback for this button to add the widget "list_entry" into the GtkListBox in the right pane. It does so after changing the label of the widget from "label" to the text present in a text entry present just above it. So, basically this button add a new entry into a list placed in the right pane(might be seen empty). This entry is a simple widget consisting of an icon and a label( at the bottom).

Now, I want the button "Add to list" to create new copies of this entry every time I click it and append that entry to the list in the right pane. But every time I add a new entry to the list, it simply overwrite the previous entry of the list and gives a warning -> Attempting to add a widget with type GtkBox to a container of type GtkListBoxRow, but the widget is already inside a container of type GtkListBoxRow, please remove the widget from its existing container first.

I am using GtkListBox for the list in the right pane and the GtkBox for the new entry that I am supposed to add.

This is the code for the "click" callback of the button "Add to list"

static void
dw_left_add_btn_cb(CcPrintersPanel * self){
    GtkLabel* row_list_label = (GtkLabel*) gtk_builder_get_object (self->builder, "list_entry_label");

    GtkEntry* text_entry_to_add = (GtkEntry*) gtk_builder_get_object (self->builder, "dw_left_enter_text");

    // debug
    if ( self->list_serv == NULL || row_list_label == NULL) g_debug ("One of object for generating the list did'nt load up in the builder");

    gtk_label_set_label (row_list_label, gtk_entry_get_text (text_entry_to_add));

    gtk_entry_set_text(text_entry_to_add,"");

    GtkWidget* row_list = (GtkWidget*) gtk_builder_get_object (self->builder, "list_entry");

    gtk_list_box_insert (self->list_serv, row_list, -1);
    
}

I wanted to ask you how to create an entirely new widget( for every new entry ) from a widget that was loaded into Builder using a .ui file. Please also advise me if you have some other way of implementing this.


Solution

  • GtkBuilder is not a factory of widgets. It's more like a carton of widgets. Some pseudocode:

    GtkWidget *widget1, *widget2;
    
    builder = gtk_builder_new();
    widget1 = gtk_builder_get_object(builder, "label");
    widget2 = gtk_builder_get_object(builder, "label"); // this will not produce another label but return existing one
    // (widget1 == widget2), they point to same object
    
    // let's unpack another carton of widgets...
    builder2 = gtk_builder_new(); 
    widget2 = gtk_builder_get_object(builder2, "label");
    // (widget1 != widget2), now that's really 2 distinct widgets
    

    Hence the warning. You try to add widget to a ListBoxRow, but this exact widget is already in a ListBoxRow. When you want to dynamically create another widget, you must create another GtkBuilder.

    static void
    dw_left_add_btn_cb(CcPrintersPanel * self){
        GtkBuilder *b = gtk_builder_new();
        GtkLabel* w = (GtkLabel*) gtk_builder_get_object (b, "list_entry_label");
    
        gtk_list_box_insert (self->list_serv, w, -1);
    }