Re: Separation between GUI and main
Tristan Van Berkom <[email protected]>
| Newsgroups | gmane.comp.gnome.glade.user |
|---|---|
| Message-ID | <CAGUy9WLtYQW7WBQKGn1Nxi9EAoiJf=TCmB+FsHFFYiijKQiP_w@mail.gmail.com> |
On Sat, Jan 21, 2012 at 12:44 AM, Manuel Ferrero <[email protected]> wrote: > I'm learning GTK+ and Glade on my win32 machine. > > Right now I was able to write, compile and run a simple code with a window, > an hbox and a toggle button in it. > When the user presses the button I display the state of the button via the > callback function. > > The main function is this: > > ---SNIP--- > int main(int argc, char *argv[]) > { > gtk_init(&argc, &argv); > > GtkBuilder *builder_handler; > GtkWidget *window; > GtkWidget *connect_button; > > builder_handler = gtk_builder_new(); > gtk_builder_add_from_file(builder_handler, GUI_XML_FILENAME, NULL); > > window = GTK_WIDGET(gtk_builder_get_object(builder_handler, "window")); > connect_button = GTK_WIDGET(gtk_builder_get_object(builder_handler, > "connect_button")); > > gtk_builder_connect_signals(builder_handler, NULL); > g_object_unref (G_OBJECT (builder_handler)); > > gtk_widget_show (connect_button); > gtk_widget_show (window); > > > gtk_main (); > > return 0; > } // main > ---PINS--- > > I'll spare you the callbacks. > > Now my question is this: with Glade I add another button (expanding the hbox > of course) and I name it my_button_2. > The code has to know about this new button so at least I have to declare a > new GtkWidget pointer, call the gtk_builder_get_object() to assing the > pointer and then show it with a gtk_widget_show(). > Leave alone the callbacks for all the signals. > > I don't understand how this can separate the GUI from the code. > Am I missing something? > Is tehre some way to connect signals without knowing the objects? In this > case I could only write the needed callbacks to manage the new button. If you need to control the state of a widget in the interface, you need a pointer to that widget. If you add a widget to your interface, say a button that causes a new action you need to handle, then you don't need a pointer to that button. A common practice is to use the last argument of gtk_builder_connect_signals(), you can create a data structure which contains the needed pointers for your whole module, i.e. typedef struct _MyModule { GtkWidget *the_toggle_button; GtkWidget *the_entry; GtkWidget *the_toplevel_window; GtkWidget *etc, *etc; }; { MyModule module = { 0, }; /* where you load the gui file */ builder = gtk_builder_new (); gtk_builder_add_from_file (...); module.the_toggle_button = gtk_builder_get_object (builder, "the-toggle-button"); ... etc etc ... /* then just pass your main module structure to all of your callback */ gtk_builder_connect_signals (builder, &module); } This is common practice but still old-fashioned if you ask me. Better practice still, is to derive a GtkContainer for every modular GUI object which can be used and reused throughout your GUI. Then you repeat the above exercise in the object's ->constructed() method, pass the object's instance as the user data for all callbacks and have one GtkBuilder xml definition for each composite object which you might use in your GUI. You might have a GUI file describing the layout of your preferences dialog, your project properties dialog etc. Then if you are developing an editor program which might have multiple projects loaded, you might be allowed to display project properties dialogs for different projects at the same time. Then your properties dialog (which derives from GtkDialog and has it's contents defined by a GtkBuilder xml file which is added to the dialog at ->constructor() time)... would have a "project" property. At which point, creating a preferences dialog can be done at any time with a call to: new_dialog = g_object_new (MY_TYPE_CUSTOM_PROPERTIES_DIALOG, "project", the_project_to_display_properties_for, NULL); Admittedly, with this paradigm, you shouldnt really have to be doing things by hand in your ->constructor() method... or accessing GtkBuilder apis manually at all... this is just because we have not yet landed something at the GtkContainer level to allow you to simply assign GtkBuilder xml to a container class (in other words, we are actually still a step behind NextStep in this respect). To answer your question about "separating your GUI from your code", of course you will always need to declare object members for the widgets that you actually need to access, adding these members only ever happens when your program gains new features, and those features require interaction with the GUI. In earlier times, GUIs were constructed in actual code, i.e.: window = gtk_window_new(); box = gtk_box_new (...); gtk_widget_show (box); gtk_container_add (GTK_CONTAINER (window), box); /* ... huge code to construct menu bar ... */ gtk_widget_show (menubar); gtk_container_add (GTK_CONTAINER (box), menubar); /* huge code to construct the rest of your application... etc etc */ In the first versions of Glade, it was only possible to use with code generation, this ended up in the mixing of business logic in generated C code files, rendering it virtually impossible to ever modify your GUI after you initially developped it (or just very very impractical, because then you have to re-merge in all of your business logic... just because you wanted to add some icon to a menu item or add some alignment to a frame or whatever minor detail you wanted to change). Using xml to define the actual interface makes UI coding practical and maintainable, it separates the files in which you store your code and the files in which you store your interface definition (note also that you can always put your GtkBuilder xml into a header file as a string constant as a step in your compilation, and include the GtkBuilder xml if you are not content with accessing the hard-drive just to fire up a new dialog... or if you just want to avoid the complexity of resolving system installation paths at runtime). Cheers, -Tristan > Please remember I'm really new to this programming style, I'm an embedded C > programmer so I know nealry nothign about objects and events. > > Thanks in advance. > -- > Regards, > Manuel Ferrero > R&D department > > Reer SpA > Tel. +39 011 2482215 > Fax. +39 011 859867 > > L'utilizzo non autorizzato del presente messaggio e' vietato e potrebbe > costituire reato. > Se il presente messaggio non e' a Lei indirizzato, il suo contenuto non deve > essere considerato > come trasmesso o autorizzato dalla Reer SpA; in tale caso Le saremmo grati > se, via e-mail, > ce ne comunicasse l'errata ricezione. > > The unauthorized use of this e-mail is prohibited and could constitute an > offence. > If you are not the intended recipient of this message its contents shall be > understood as neither > given nor endorsed by Reer SpA. Please notify Reer SpA by e-mail immediately > in that case. > > _______________________________________________ > Glade-users maillist - [email protected] > http://lists.ximian.com/mailman/listinfo/glade-users _______________________________________________ Glade-users maillist - [email protected] http://lists.ximian.com/mailman/listinfo/glade-users