[Glade-users] Separation between GUI and main



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




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]