IV. Comment afficher plusieurs widgets▲
IV-A. Aperçu▲
IV-B. Le problème▲
Dans la partie précédente, nous avons réussi à afficher un bouton dans la fenêtre de notre application. Si vous avez essayé d'ajouter un second widget, GTK+ a dû vous répondre poliment :
(gtk_box.exe:492) : Gtk-WARNING **: Attempting to add a widget with type
GtkButton to a GtkWindow, but as a GtkBin subclass a GtkWindow can only contain
one widget at a time; it already contains a widget of type GtkButton
Les plus anglophiles d'entre vous auront compris que GTK+ n'accepte pas l'ajout un second widget dans notre fenêtre tout simplement parce qu'il y en a déjà un et que la sous-classe GtkBin (classe mère de notre GtkWindow) ne peut contenir qu'un seul widget.
IV-C. La solution▲
Pour contourner ce problème, il faut commencer par créer un widget qui accepte d'en contenir plusieurs autres, pour ensuite y ajouter tout ce dont nous avons besoin. Pour l'instant, nous utiliserons qu'un seul widget (il existe trois classes qui permettent ceci), il s'agit des GtkBox. Il s'agit de la méthode que j'utilise le plus souvent. Ce n'est peut-être pas la plus simple à maîtriser, mais elle extrêmement souple et puissante. Elle consiste à créer une boîte puis à y ajouter les widgets les uns après les autres (soit au début soit à la fin). Il existe deux classes héritant de GtkBox : les GtkVBox qui empilent les widgets dans le sens vertical et les GtkHBox qui font de même, mais dans le sens horizontal. Les fonctions pour manipuler ces deux classes sont les mêmes, seule la fonction pour les créer porte un nom différent :
GtkWidget *
gtk_vbox_new (
gboolean homogeneous, gint spacing);
GtkWidget *
gtk_hbox_new (
gboolean homogeneous, gint spacing);
Le paramètre homogeneous permet de réserver pour chaque widget une zone de taille identique (zone que le widget n'est pas obligé de remplir) et spacing permet d'ajouter une bordure en pixels (espacement autour de la GtkBox). Ensuite, il suffit d'ajouter les différents widgets grâce aux fonctions :
void
gtk_box_pack_start (
GtkBox *
box, GtkWidget *
child, gboolean expand, gboolean fill, guint padding);
void
gtk_box_pack_end (
GtkBox *
box, GtkWidget *
child, gboolean expand, gboolean fill, guint padding);
qui ajoutent réciproquement le widget child au début et à la fin de box. Le paramètre expand permet au widget d'avoir le plus de place possible (si le paramètre homogeneous vaut TRUE, cette option n’a aucun effet). Si plusieurs widgets ont ce paramètre à TRUE, ils se partagent de façon égale l'espace. L'option fill permet au widget de remplir tout l'espace qui lui ait réservé.
Pour réellement comprendre l'influence de ces paramètres, il faut faire des tests en modifiant un à un chaque paramètre et observer les effets d'un redimensionnement de la fenêtre principale.
Le plus gênant avec cette méthode c'est qu'il faut jongler entre les GtkHBox et les GtkVBox en les imbriquant pour obtenir le résultat souhaité : n'hésitez pas à utiliser une feuille et un crayon ;)
Pour en revenir à notre éditeur de texte, nous allons préparer notre application à contenir les futurs widgets. Nous utilisons un GtkVBox pour l'ensemble des widgets (il s'agit de la boîte principale qui pourra contenir d'autres GtkContainer selon nos besoins) :
#include <stdlib.h>
#include <gtk/gtk.h>
#include "callback.h"
int
main (
int
argc, char
**
argv)
{
GtkWidget *
p_window =
NULL
;
GtkWidget *
p_main_box =
NULL
;
/* Initialisation de GTK+ */
gtk_init (&
argc, &
argv);
/* Creation de la fenetre principale de notre application */
p_window =
gtk_window_new (
GTK_WINDOW_TOPLEVEL);
g_signal_connect (
G_OBJECT (
p_window), "
destroy
"
, G_CALLBACK (
cb_quit), NULL
);
/* Creation du conteneur principal */
p_main_box =
gtk_vbox_new (
FALSE, 0
);
gtk_container_add (
GTK_CONTAINER (
p_window), p_main_box);
/* Creation du bouton "Quitter" */
{
GtkWidget *
p_button =
NULL
;
p_button =
gtk_button_new_from_stock (
GTK_STOCK_QUIT);
g_signal_connect (
G_OBJECT (
p_button), "
clicked
"
, G_CALLBACK (
cb_quit), NULL
);
gtk_box_pack_start (
GTK_BOX (
p_main_box), p_button, FALSE, FALSE, 0
);
}
/* Affichage de la fenetre principale */
gtk_widget_show_all (
p_window);
/* Lancement de la boucle principale */
gtk_main (
);
return
EXIT_SUCCESS;
}