c - GTK pass user data to callback using Glade -
i notice glade allows set object passed within user data part of gtk callback.
is there way can pass integer value instead?
i have set of menu items point @ same callback function, small section of code need identify menu item 1 called callback.
note: signals setup automatically glade_xml_signal_autoconnect, , perfer keep way.
in opinion respect glade , callbacks 1 have goodbye notion of passing 1 single element callbacks. , stop using glade
in order configure user data passed specific callback.
i used pass struct named app
callbacks contains pointer every ui element loaded ui definitions file , instantiated gtkbuilder
. stops tedious task in glade
of clicking , forth between widgets set user data of callbacks. in addition ui elements, of time struct contains further elements important @ runtime on application level.
a benefit of approach not tempted think how implement individual callback should act upon more 1 element case. people tackle grouping widgets of interest container. in order pass widgets callback pass container. in callback widgets calling gtk_container_get_children
or similar functions. approach makes callbacks illegible , reduce fun while editing code.
if every callback has elements available should manipulated @ runtime don't have care implementing single callback since every callback shares same structure.
further created helper macro defines pointer instantiated element name of glade id. way elements definitions in code in sync displayed in glade. makes renaming of widgets easy (substitute name in sources + glade file).
to illustrate approach have appended files of sample program. don't scared of number of files. dividing program logical units/modules makes programming simpler. quick view of whole project created git repository on github:
just compare callbacks.c
callback file(s). interested know how compare respect legibility , structure , taking account may have element-ids glade
still in mind.
callbacks.c
:
#include "app.h" void button1_clicked_cb (gtkbutton * button, app * app) { get_ui_element (gtkentry, entry1); if (gtk_entry_get_text_length (entry1) == 0) gtk_entry_set_text (entry1, "test"); else gtk_entry_set_text (entry1, ""); } void button2_clicked_cb (gtkbutton * button, app * app) { gboolean active; get_ui_element (gtkspinner, spinner1); get_ui_element (gtkwidget, eventbox1); g_object_get (g_object (spinner1), "active", &active, null); if (active) { gtk_spinner_stop (spinner1); gtk_widget_override_background_color (eventbox1, gtk_state_flag_normal, app-> active_color); } else { gtk_spinner_start (spinner1); gtk_widget_override_background_color (eventbox1, gtk_state_flag_normal, app-> inactive_color); } } void button3_clicked_cb (gtkbutton * button, app * app) { gdkrgba bg = { 0, 0, 1, 1 }; get_ui_element (gtkwidget, eventbox1); gtk_widget_override_background_color (eventbox1, gtk_state_flag_normal, &bg); } void button4_clicked_cb (gtkbutton * button, app * app) { const gchar *str; get_ui_element (gtklabel, label1); str = gtk_label_get_text (label1); if (strcmp (str, "label") == 0) { gtk_label_set_text (label1, "newtext"); } else { gtk_label_set_text (label1, "label"); } } void button5_clicked_cb (gtkbutton * button, app * app) { get_ui_element (gtkwidget, button1); get_ui_element (gtkwidget, button2); get_ui_element (gtkwidget, button4); g_signal_emit_by_name (button1, "clicked", app); g_signal_emit_by_name (button2, "clicked", app); g_signal_emit_by_name (button4, "clicked", app); }
main.c
:
#include "app.h" int main (int argc, char *argv[]) { app *app; app = (app *) g_new (app, 1); gtk_init (&argc, &argv); app_init (app); get_ui_element (gtkwidget, window1); gtk_widget_show_all (window1); gtk_main (); return 0; }
app.c
:
#include "app.h" gobject * app_get_ui_element (app * app, const gchar * name) { const gchar *s; gslist *list; list = app->objects; { s = gtk_buildable_get_name (list->data); if (strcmp (s, name) == 0) { return list->data; } } while (list = g_slist_next (list)); return null; } void app_init_colors (app * app) { gdkrgba active_color = { 1, 0, 0, 1 }; gdkrgba inactive_color = { 0, 1, 0, 1 }; app->active_color = g_new0 (gdkrgba, 1); app->inactive_color = g_new0 (gdkrgba, 1); app->active_color = gdk_rgba_copy (&active_color); app->inactive_color = gdk_rgba_copy (&inactive_color); } void app_init (app * app) { gerror *err = null; app->definitions = gtk_builder_new (); gtk_builder_add_from_file (app->definitions, ui_definitions_file, &err); if (err != null) { g_printerr ("error while loading app definitions file: %s\n", err->message); g_error_free (err); gtk_main_quit (); } gtk_builder_connect_signals (app->definitions, app); app->objects = gtk_builder_get_objects (app->definitions); app_init_colors (app); }
app.h
:
#ifndef __app__ #define __app__ #include <gtk/gtk.h> #define ui_definitions_file "ui.glade" #define get_ui_element(type, element) type *element = (type *) \ app_get_ui_element(app, #element); typedef struct app_ { gtkbuilder *definitions; gslist *objects; gdkrgba *active_color; gdkrgba *inactive_color; } app; void app_init (app * ); gobject * app_get_ui_element (app * , const gchar * ); #endif
ui.glade
:
<?xml version="1.0" encoding="utf-8"?> <interface> <!-- interface-requires gtk+ 3.0 --> <object class="gtkwindow" id="window1"> <property name="can_focus">false</property> <property name="border_width">20</property> <signal name="destroy" handler="gtk_main_quit" swapped="no"/> <child> <object class="gtkgrid" id="grid1"> <property name="visible">true</property> <property name="can_focus">false</property> <property name="row_spacing">10</property> <property name="column_spacing">20</property> <child> <object class="gtkspinner" id="spinner1"> <property name="visible">true</property> <property name="can_focus">false</property> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">1</property> <property name="width">2</property> <property name="height">1</property> </packing> </child> <child> <object class="gtkeventbox" id="eventbox1"> <property name="height_request">50</property> <property name="visible">true</property> <property name="can_focus">false</property> <child> <placeholder/> </child> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">2</property> <property name="width">2</property> <property name="height">1</property> </packing> </child> <child> <object class="gtkentry" id="entry1"> <property name="visible">true</property> <property name="can_focus">true</property> <property name="invisible_char">•</property> <property name="invisible_char_set">true</property> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">0</property> <property name="width">2</property> <property name="height">1</property> </packing> </child> <child> <object class="gtklabel" id="label1"> <property name="visible">true</property> <property name="can_focus">false</property> <property name="label" translatable="yes">label</property> </object> <packing> <property name="left_attach">1</property> <property name="top_attach">3</property> <property name="width">2</property> <property name="height">1</property> </packing> </child> <child> <object class="gtkbuttonbox" id="buttonbox1"> <property name="visible">true</property> <property name="can_focus">false</property> <property name="spacing">10</property> <property name="layout_style">center</property> <child> <object class="gtkbutton" id="button1"> <property name="label" translatable="yes">toggle entry</property> <property name="use_action_appearance">false</property> <property name="visible">true</property> <property name="can_focus">true</property> <property name="receives_default">true</property> <property name="use_action_appearance">false</property> <signal name="clicked" handler="button1_clicked_cb" swapped="no"/> </object> <packing> <property name="expand">false</property> <property name="fill">true</property> <property name="position">0</property> </packing> </child> <child> <object class="gtkbutton" id="button2"> <property name="label" translatable="yes">toggle spinner + bg</property> <property name="use_action_appearance">false</property> <property name="visible">true</property> <property name="can_focus">true</property> <property name="receives_default">true</property> <property name="use_action_appearance">false</property> <signal name="clicked" handler="button2_clicked_cb" swapped="no"/> </object> <packing> <property name="expand">false</property> <property name="fill">true</property> <property name="position">1</property> </packing> </child> <child> <object class="gtkbutton" id="button3"> <property name="label" translatable="yes">set bg</property> <property name="use_action_appearance">false</property> <property name="visible">true</property> <property name="can_focus">true</property> <property name="receives_default">true</property> <property name="use_action_appearance">false</property> <signal name="clicked" handler="button3_clicked_cb" swapped="no"/> </object> <packing> <property name="expand">false</property> <property name="fill">true</property> <property name="position">2</property> </packing> </child> <child> <object class="gtkbutton" id="button4"> <property name="label" translatable="yes">toggle label</property> <property name="use_action_appearance">false</property> <property name="visible">true</property> <property name="can_focus">true</property> <property name="receives_default">true</property> <property name="use_action_appearance">false</property> <signal name="clicked" handler="button4_clicked_cb" swapped="no"/> </object> <packing> <property name="expand">false</property> <property name="fill">true</property> <property name="position">3</property> </packing> </child> <child> <object class="gtkbutton" id="button5"> <property name="label" translatable="yes">toggle everything</property> <property name="use_action_appearance">false</property> <property name="visible">true</property> <property name="can_focus">true</property> <property name="receives_default">true</property> <property name="use_action_appearance">false</property> <signal name="clicked" handler="button5_clicked_cb" swapped="no"/> </object> <packing> <property name="expand">false</property> <property name="fill">true</property> <property name="position">4</property> </packing> </child> </object> <packing> <property name="left_attach">0</property> <property name="top_attach">5</property> <property name="width">4</property> <property name="height">1</property> </packing> </child> <child> <object class="gtkseparator" id="separator1"> <property name="visible">true</property> <property name="can_focus">false</property> </object> <packing> <property name="left_attach">0</property> <property name="top_attach">4</property> <property name="width">4</property> <property name="height">1</property> </packing> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> <child> <placeholder/> </child> </object> </child> </object> </interface>
Comments
Post a Comment