[Glade-users] Separation between GUI and main



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>




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