[Glade-users] Separation between GUI and main
Tristan Van Berkom
tristan.van.berkom at gmail.com
Sat Jan 21 10:10:57 UTC 2012
Ok here's a tiny tarball demonstrating the concept.
Just untar and make it... see my-demo.c to see how it works.
It's very simple and modular, lately I've been doing work with
ClutterScript and sometimes Mx, I use the same approach
with Clutter effectively it works the same way.
Note that IMO, the whole business in the ->constructor()
should not be needed, this can effectively be implemented
as a feature of GtkContainerClass, one would only have
to associate some G_STRUCT_OFFSETs on the instance
or private data to determine where composite children
pulled from the UI should be assigned after the container
class constructs (just a bit of syntactic sugar).
Note that I have created a branch in GTK+ in the past that
does this, it's called "composite-containers", actually it needs
some work to integrate the files as string constants in the
build system and improve the APIs which determine how
to automatically pull children from the associated builder
xml.
There is also an blog post I wrote on this subject:
http://blogs.gnome.org/tvb/2010/03/08/it-was-a-saturday-afternoon-patch/
Merry Christmas,
-Tristan
On Sat, Jan 21, 2012 at 2:31 PM, Igor Chetverovod <chetverovod at gmail.com> wrote:
> Hello Tristan,
>
> Could you please to provide more detailed example for this part of your letter:
> "...Better practice still, is to derive a GtkContainer for every modular
> GUI object which can be used and reused throughout your GUI..." ?
>
> I am not novice in using of GTK and glade, but I did not catch the
> work flow of mentioned new technic. It would be great to see a pice of
> code.
>
> Thank you,
>
> Igor
>
> 2012/1/20, Tristan Van Berkom <tristan.van.berkom at gmail.com>:
>> On Sat, Jan 21, 2012 at 12:44 AM, Manuel Ferrero <mferrero at reer.it> 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 - Glade-users at lists.ximian.com
>>> http://lists.ximian.com/mailman/listinfo/glade-users
>> _______________________________________________
>> Glade-users maillist - Glade-users at lists.ximian.com
>> http://lists.ximian.com/mailman/listinfo/glade-users
>>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: demo.tgz
Type: application/x-gzip
Size: 2296 bytes
Desc: not available
URL: <http://lists.ximian.com/pipermail/glade-users/attachments/20120121/925afdef/attachment-0001.bin>
More information about the Glade-users
mailing list