Search code examples
ccheckboxdynamicgtk3children

How to access dynamically created GTK Checkbutton in plain C


I created a program that outputs CSV formatted tags based on checkbuttons.. There's a LOT of them so it only makes sense to create them programmatically.. I was successful in that sense, but I was never able to figure out how to get their checked state since you can't access them like normal checkbuttons. I worked around it, but now getting to the 'polishing' phase of my program, I'd REALLY like to be able to reset the form by unchecking them all, and I can't figure out how to access them.. First, here's how the checkbuttons are created dynamically:

        for (int x = 0; x <= NUMBER_OF_STRING; x++)
        {
            if (tagArray[x] != NULL && strcmp(tagArray[x], "\0"))
            {
                dynamic_checkBox = gtk_check_button_new_with_label(tagArray[x]);
                gtk_container_add(GTK_CONTAINER(flowBox), dynamic_checkBox);
                g_signal_connect(dynamic_checkBox, "toggled", G_CALLBACK(check_state), (gpointer)tagArray[x]);
            }
        }

So that works just fine.. I was able to use a little 'hack' creating an extra char array and putting 'true' or 'false' strings in there and using strcmp() to basically write my own checked/unchecked state to an array with the gpointer data, but as with most hacks, if you're not doing it right it comes back to get ya.. Now I can't figure out how to uncheck all the boxes and reset the form..

static void uncheck_button_clicked(GtkWidget* widget, gpointer data)
{
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dynamic_checkBox), FALSE);
}

As you can see, I'm calling the global GtkWidget *dynamic_checkBox but that doesn't help me because it doesn't point to the actual instance of that checkbutton I need.. So how do I go about accessing these checkboxes? I even tried dynamically declaring new GtkWidgets with strings so I could access them, but it just lead to incompatible type errors... I've been Googling and banging my head against the wall for 2 days now with no results. Thanks in advance.


Solution

  • First of all, it doesn't make sense to use a global GtkWidget* or GtkCheckButton*, since you have multiple of them anyway, so each time you create a new one, it will overwrite the old value.

    Next, there are 2 ways of still accessing those buttons:

    • Like Alexander suggested in the comments, you can keep a list of GtkWidget* or GtkCheckButton* (and add your buttons as you create them on the go). That way, you can iterate over the array and uncheck them all.

    • Another option is to use the parent container of all the check buttons, by iterating over its children (but that really assumes you don't have any other GtkCheckButtons in there!)

    GList *children = gtk_container_get_children (GTK_CONTAINER (flowbox));
    for (GList *l = children; l; m = g_list_next (l)) {
        GtkWidget *child = l->data;
    
        // Note, you don't need this if-check if your flowbox only contains checkbuttons.
        // Bote 2: this *will* turn off also unrelated check buttons
        if (GTK_IS_CHECK_BUTTON (child)) {
            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (child), FALSE);
        }
    }
    

    As a side remark: you can use strcmp(tagArray[x], "") if you just want to check if the string is empty