Search code examples
c++castinggtkgtk2

GTK+ Use one handler for multiple widgets


I have a callback function as follows:

void handle(GtkWidget *widget, gpointer data) {...}

Since I have a lot of widgets for this window, I would like to use this callback as the only handler to avoid writing a bunch of small functions. Initially I thought of using an enum that's stored in the UI class which wraps around the window, and then I would test for it as follows:

UIClass::Signal signal = (UIClass::Signal) data;
switch (signal) {
  case UIClass::main_button:
    // handle
  case UIClass::check_box:
  ...
}

But the compiler refuses the cast in the first line of that snippet.

Is there a standard way to accomplish this? Or was GTK+ designed to have one handler for every widget?


Solution

  • Store a pointer to a widget in class and pass whole object to the handler:

    #include <gtk/gtk.h>
    #include <iostream>
    
    struct UIClass
    {
        GtkWidget* widget1, *widget2, *box;
        UIClass()
        {
            widget1 = gtk_button_new_with_label("button1");
            widget2 = gtk_button_new_with_label("button2");
    
            box = gtk_hbox_new(true, 10);
            gtk_box_pack_start(GTK_BOX(box), widget1, 0 ,0, 1);
            gtk_box_pack_start(GTK_BOX(box), widget2, 0 ,0, 1);
        }
    
        static void handle(GtkWidget* sender, UIClass* uiClass)
        {
            if(sender == uiClass->widget1)
                std::cout<<"widget1"<<std::endl;
            else if(sender == uiClass->widget2)
                std::cout<<"widget2"<<std::endl;
            else
                std::cout<<"something else"<<std::endl;
        }
    
        void connect()
        {
            g_signal_connect(widget1, "clicked", G_CALLBACK(UIClass::handle), this);
            g_signal_connect(widget2, "clicked", G_CALLBACK(UIClass::handle), this);
        }
    };
    
    int main(int argc, char *argv[])
    {
      gtk_init (&argc, &argv);
    
      GtkWidget* window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    
      UIClass ui;
      ui.connect();
    
      gtk_container_add(GTK_CONTAINER(window), ui.box);
    
      gtk_widget_show_all(window);
      gtk_main();
    
      return 0;
    }