Home > other >  How to pass 2 or more GTK widget to callback function
How to pass 2 or more GTK widget to callback function

Time:08-13

I have seen people pass a widget like this

static void on_button_click(GtkWidget *button, gpointer data) {
    gtk_label_set_label(GTK_LABEL(data), "Hello, World!");
}
...

   g_signal_connect(button, "clicked", G_CALLBACK(on_button_click), label);

but how do you pass 2 widgets like a label and an entry?

I want to write a calculator so I need to read from the entry, parse and write the results to the label when the user click (on) the button.

Thanks in advance for helping this noob.

CodePudding user response:

The last argument (gpointer data) can point to whatever you want, so options are basically limitless.

I think in order from "quick hack for a demo app" up to "scalable/maintainable for large, complex applications", some of these options might be:

  1. For a simple program with only a handful of widgets, I might be inclined to just store the GtkWidget pointers in global memory:

    GtkWidget *window;
    GtkWidget *label;
    GtkWidget *btnEnter;
    GtkWidget *btnClear;
    GtkWidget *entry;
    
    // copy entry to label for simple demo purposes
    static void on_enter_button_click(GtkWidget *button, gpointer data) {
        // data unused, just get global references to label   entry
        gtk_label_set_label(GTK_LABEL(label), gtk_entry_get_text(entry));
    }
    
    // clear the label. maybe this is another function your calculator has
    static void on_clear_button_click(GtkWidget *button, gpointer data) {
        // data unused, just get global references...
        gtk_label_set_label(GTK_LABEL(label), "");
    }
    
    int main(int argc, char**argv){
       // Initialize all the widgets here
    
       // register unique callbacks
       g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), NULL);
       g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), NULL);
    }
    
  2. You can group these into a struct if uncomfortable using global memory or want slightly more ability to scale/refactor/reuse your code:

    struct MyWidgets {
        GtkWidget *window;
        GtkWidget *label;
        GtkWidget *btnEnter;
        GtkWidget *btnClear;
        GtkWidget *entry;
    };
    
    // copy entry to label for simple demo purposes
    static void on_enter_button_click(GtkWidget *button, gpointer data) {
        struct MyWidgets *widgets = (struct MyWidgets*) data;
        gtk_label_set_label(GTK_LABEL(widgets->label), gtk_entry_get_text(widgets->entry));
    }
    
    // clear the label... maybe this is another function your calculator has?
    static void on_clear_button_click(GtkWidget *button, gpointer data) {
        struct MyWidgets *widgets = (struct MyWidgets*) data;
        // data unused, just get global references...
        gtk_label_set_label(GTK_LABEL(widgets->label), "");
    }
    
    int main(int argc, char**argv){
       struct MyWidgets widgets;
       // Initialize all the widgets here
    
       // register unique callbacks
       g_signal_connect(btnEnter, "clicked", G_CALLBACK(on_enter_button_click), &widgets);
       g_signal_connect(btnClear, "clicked", G_CALLBACK(on_clear_button_click), &widgets);
    }
    

But for something really simple, above is basically same as first example, but with extra steps :).

  1. Another alternative could be to group widgets within any GtkContainer "class",which may fall out naturally in grouping objects into a particular layout, and then use something like gtk_widget_get_parent() to get parent container, then any one of the several methods on GtkContainer that allows iterating through children.

  2. ANOTHER alternative is composite widgets. This tutorial demonstrates some of the concepts there and implements a single callback function for handling multiple widgets: https://www.cc.gatech.edu/data_files/public/doc/gtk/tutorial/gtk_tut-20.html

  • Related