Les fenêtres
Le premier élément d'une interface graphique est bien entendu
la fenêtre. Il est donc tout à fait normal que ce soit le premier
objet étudié dans le cadre de ce cours.
1. Créer et afficher une fenêtre.
Avant de commencer l'étude des fenêtres, il faut savoir que les
objets graphiques de GTK+ sont appelés des widgets. Un widget
est en fait une structure définissant les propriétés d'un
objet associée à une large panoplie de fonctions permettant de
manipuler ces objets.
Ici, le terme est à prendre au sens littéral, mais aussi au sens
Programmation Orientée Objet (POO). En effet, bien que GTK+ soit écrit
en C, il introduit la notion d'héritage et les widgets de GTK+ suivent
une hiérarchie bien définie. Ainsi tous les objets graphiques
héritent des propriétés et des fonctions d'un widget de
base qui s'appelle GtkWidget.
Ainsi le widget permettant d'afficher une fenêtre se nomme GtkWindow.
Il a bien sûr ses propres fonctions, mais grâce à l'héritage
il bénéficie aussi des fonctions de plusieurs autres widgets.
Voici donc la position de GtkWindow dans la hiérarchie GTK+ :

1.1 Création d'une fenêtre
Dans un premier temps, il faut déclarer un pointeur sur notre objet
fenêtre. Bien que nous voulions créer un objet GtkWindow, il faut
déclarer un objet GtkWidget.
GtkWidget *pWindow;
Par la suite, quel que soit l'objet à créer, il faudra toujours
déclarer un GtkWidget.
Une fois l'objet pWindow déclarer, il faut l'initialiser. Pour cela,
une fonction est à notre disposition :
GtkWidget* gtk_window_new(GtkWindowType type);
Le paramètre type définit le type de la fenêtre
en cours de création, et peut prendre une des deux valeurs suivantes
:
- GTK_WINDOW_TOPLEVEL : pour créer une fenêtre complète
avec une zone réservée dans la barre des tâches ;
- GTK_WINDOW_POPUP : pour créer une fenêtre sans aucune décoration
(barre de titre, bordure, ...).
La valeur de retour est le pointeur sur notre nouvel objet fenêtre. Cette
fonction est donc à utiliser comme ceci :
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
La création de la fenêtre est maintenant terminée.
1.2 Affichage de la fenêtre.
Un widget n'a pas de fonction spécifique liée à son affichage,
mais utilise une fonction de GtkWidget qui est :
void gtk_widget_show(GtkWidget *widget);
Il suffit donc de passer en paramètre le widget que nous voulons afficher,
ainsi pour afficher notre fenêtre, la ligne de code est :
gtk_widget_show(pWindow);
Au contraire, pour détruire la fenêtre, la fonction sera :
void gtk_widget_destroy(GtkWidget *widget);
Voici donc le code source complet de notre programme affichant une fenêtre.
#include <stdlib.h>
#include <gtk/gtk.h> int
main(int argc,char
**argv)
{
/* Declaration du widget
*/
GtkWidget *pWindow;
gtk_init(&argc,&argv);
/* Creation de la fenetre
*/
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Affichage de la fenetre
*/
gtk_widget_show(pWindow);
/* Destruction de la fenetre
*/
gtk_widget_destroy(pWindow);
return EXIT_SUCCESS;
} |
En essayant ce programme, vous ne verrez sûrement pas la fenêtre
s'afficher. La raison est simple : la destruction de la fenêtre a lieu
tout de suite après son affichage. Nous allons maintenant étudier
la théorie de signaux afin que l'application ne se termine qu'au moment
où l'utilisateur le demande.
1.3 Les signaux.
Nous allons maintenant étudier comment faire réagir une application
GTK+ aux actions de l'utilisateur.
Dans un premier temps, lorsque l'utilisateur interagie avec l'application (clique
sur un bouton, ferme une fenêtre, ...), le widget concerné émet
un signal (par exemple "destroy" lorsque l'on ferme une fenêtre).
Chaque widget est associé à un ou plusieurs signaux et permet
donc ainsi de programmer toutes les actions possibles.
Ce signal va ensuite être intercepté par une boucle évènementielle
qui va vérifier qu'une action spécifique à ce signal et
ce widget a bien été définie. Si tel est le cas, la fonction
associée sera exécutée. Ce type de fonction s'appelle fonction
callback.
Il faut donc créer une fonction callback pour chacun des évènements
susceptible d'avoir lieu pendant l'exécution du programme et associer
(ou connecter) cette fonction à un signal.
La première étape consiste donc à créer une fonction
callback. Dans la majorité des cas, une fonction callback sera de cette
forme :
void nom_de_la_fonction(GtkWidget *widget, gpointer data)
Le paramètre widget est le widget qui a émis
le signal, et data est une donnée supplémentaire
qui peut être utilisée.
Ensuite, pour connecter un signal à une fonction callback, GTK+ utilise
une fonction de la bibliothèque GLib qui est :
gulong g_signal_connect(gpointer *object, const gchar *name,
GCallback func, gpointer func_data );
Le premier paramètre object, correspond au widget
qui émet le signal. Cependant, la variable demandée par g_signal_connect
étant de type gpointer* (correspond à void*
du C standard) et le widget de type GtkWidget*, il faut convertir
ce dernier pour ne pas provoquer d'erreur lors de la compilation. Pour cela
GTK+ (ou dans ce cas GLib) fourni une macro de conversion (G_OBJECT)
qui sera à utiliser à chaque utilisation de cette fonction.
Le second paramètre name, est le signal qui doit
être intercepter par la boucle évènementielle. Dans ce cours,
certains signaux seront utilisés dans les exemples, mais la rubrique
"En savoir plus" donnera une liste complète des signaux qui
peuvent être émis par un widget.
Le troisième paramètre func, définit
la fonction callback à associer au signal. Cette fois encore, il faudra
utiliser une macro de conversion qui est G_CALLBACK(func).
Le dernier paramètre func_data, permet de spécifier
une donnée quelconque à laquelle la fonction callback peut avoir
accès pour effectuer son travail correctement.
Une fois que les signaux sont connectés, il faut lancer la boucle évènementielle
en appelant cette fonction :
void gtk_main(void);
Cela aura pour effet de faire entrer GTK+ dans une boucle infinie qui ne pourra
être stoppée que par l'appel de la fonction de fin de boucle qui
est :
void gtk_main_quit(void);
Ces fonctions correspondent au minimum afin de pouvoir créer une application
GTK+ correcte. D'autres fonctions permettent une utilisation avancée
des signaux et de la boucle évènementielle et seront traitées
dans un autre chapitre du cours.
1.4 Exemple
Nous allons maintenant faire en sorte que la fenêtre crée reste
visible jusqu'à que l'utilisateur clique sur la croix située à
droite de la barre de titre.
La première étape est la déclaration de la fonction callback
:
void OnDestroy(GtkWidget *pWidget, gpointer pData);
La seule action que doit faire cette fonction est d'arrêter la boucle
évènementielle. La seule instruction à ajouter est donc
gtk_main_quit(); .
Il faut ensuite connecter le signal "destroy" de la fenêtre
à cette fonction :
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(OnDestroy),
NULL);
Et pour terminer, il faut lancer la boucler évènementielle.
gtk_main();
Voici donc le code source complet de notre application affichant une fenêtre.
#include <stdlib.h>
#include <gtk/gtk.h> void
OnDestroy(GtkWidget *pWidget, gpointer pData);
int main(int
argc,char **argv)
{
/* Declaration du widget
*/
GtkWidget *pWindow;
gtk_init(&argc,&argv);
/* Creation de la fenetre
*/
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Connexion du signal "destroy"
*/
g_signal_connect(G_OBJECT(pWindow), "destroy",
G_CALLBACK(OnDestroy), NULL);
/* Affichage de la fenetre
*/
gtk_widget_show(pWindow);
/* Demarrage de la boucle
evenementielle */
gtk_main();
return EXIT_SUCCESS;
}
void OnDestroy(GtkWidget *pWidget, gpointer
pData)
{
/* Arret de la boucle evenementielle
*/
gtk_main_quit();
} |
| Résultat :

|
2. Personnaliser une fenêtre
Nous allons maintenant étudier quelques fonctions permettant de modifier
l'aspect de la fenêtre précédemment créée.
L'exemple final consistera à créer une fenêtre de taille
320x200 au centre de l'écran ayant pour titre "Chapitre I.".
2.1 Position de la fenêtre
La première fonction étudiée permet de définir
la position de la fenêtre avant son affichage. Son prototype est le suivant
:
void gtk_window_set_position(GtkWindow* window, GtkWindowPosition
position);
Le premier paramètre correspond à la fenêtre dont on veut
spécifier la position. Ce paramètre étant de type GtkWindow*,
il faudra convertir la fenêtre (de type GtkWidget*) avec
la macro GTK_WINDOW.
Le deuxième paramètre est la position que l'on veut donner à
la fenêtre. Les valeurs acceptées sont :
GTK_WIN_POS_NONE : la fenêtre aura une position aléatoire
lors de son affichage ;
GTK_WIN_POS_CENTER : la fenêtre sera centrée à
l'écran ;
GTK_WIN_POS_MOUSE : le coin supérieur droit de la fenêtre
correspondra à la position de la souris au moment de l'affichage ;
GTK_WIN_POS_CENTER_ALWAYS : la fenêtre sera centrée
et ne pourra être déplacée ;
GTK_WIN_POS_CENTER_ON_PARENT : la fenêtre sera centrée
par rapport à la fenêtre parente (notion abordée dans
le prochain chapitre).
La deuxième fonction est utilisable à tout moment du programme
et permet de donner la position exacte de la fenêtre :
void gtk_window_move(GtkWindow *window, gint x, gint y);
Le premier paramètre est toujours la fenêtre dont on veut modifier
la position.
Les deux autres paramètres sont la nouvelle position de la fenêtre.
Le paramètre x est la position suivant l'axe X (axe
horizontal) et le paramètre y, la position suivant
l'axe Y (axe vertical). Le type gint est le type int
du C.
A l'inverse, pour connaître la position de la fenêtre, il faut
utiliser cette fonction :
void gtk_window_get_position(GtkWindow *window, gint *root_x,
gint *root_y);
Les paramètres correspondent aux même valeurs que pour la fonction
gtk_window_move.
Pour le programme exemple, le plus simple est d'utiliser la première
fonction ainsi :
gtk_window_set_position(GTK_WINDOW(pWindow), GTK_WIN_POS_CENTER);
2.2 Titre de la fenêtre.
Cette fois-ci, une seule fonction est à notre disposition pour modifier
le titre de la fenêtre. Cette dernière est très simple d'utilisation
:
void gtk_window_set_title (GtkWindow* window, const gchar*
title)
Le deuxième paramètre title est bien entendu
le titre que l'on veut donner à la fenêtre (gchar
correspond à char en C).
Pour l'exemple, la ligne de code sera :
gtk_window_set_title(GTK_WINDOW(pWindow), "Chapitre I.");
Pour connaître le titre d'une fenêtre, la fonction est :
G_CONST_RETURN gchar* gtk_window_get_title (GtkWindow *window);
La variable qui recevra la valeur de retour de cette fonction devra être
de type const gchar*.
2.3 Taille de la fenêtre
La fonction pour définir la taille par défaut de la fenêtre
est :
void gtk_window_set_default_size(GtkWindow* window, gint width,
gint height);
Le paramètre width est la largeur de la fenêtre
tandis que le paramètre height est sa hauteur.
Pour notre exemple, la ligne de code sera :
gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
Et très logiquement, la fonction pour connaître la taille par
défaut de la fenêtre est :
void gtk_window_get_default_size (GtkWindow *window, gint
*width, gint *height);
2.4 Programme exemple
#include <stdlib.h>
#include <gtk/gtk.h> void
OnDestroy(GtkWidget *pWidget, gpointer pData);
int main(int
argc,char **argv)
{
/* Declaration du widget
*/
GtkWidget *pWindow;
gtk_init(&argc,&argv);
/* Creation de la fenetre
*/
pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Definition de la position
*/
gtk_window_set_position(GTK_WINDOW(pWindow), GTK_WIN_POS_CENTER);
/* Definition de la taille
de la fenetre */
gtk_window_set_default_size(GTK_WINDOW(pWindow),
320, 200);
/* Titre de la fenetre */
gtk_window_set_title(GTK_WINDOW(pWindow), "Chapitre
I.");
/* Connexion du signal
"destroy" */
g_signal_connect(G_OBJECT(pWindow), "destroy",
G_CALLBACK(OnDestroy), NULL);
/* Affichage de la fenetre
*/
gtk_widget_show(pWindow);
/* Demarrage de la boucle
evenementielle */
gtk_main();
return EXIT_SUCCESS;
}
void OnDestroy(GtkWidget *pWidget, gpointer
pData)
{
/* Arret de la boucle evenementielle
*/
gtk_main_quit();
} |
| Résultat :

|
3. En savoir plus :
3.1 Signaux
| activate-default |
Prototype fonction callback : void user_function(GtkWindow
*window, gpointer user_data); |
| activate-focus |
Prototype fonction callback : void user_function(GtkWindow
*window, gpointer user_data); |
| frame-event |
Prototype fonction callback : gboolean user_function
(GtkWindow *window, GdkEvent *event, gpointer user_data); |
| keys-changed |
Prototype fonction callback : void user_function(GtkWindow
*window, gpointer user_data); |
| move-focus |
Prototype fonction callback : void user_function
(GtkWindow *window, GtkDirectionType arg1, gpointer user_data); |
| set-focus |
Prototype fonction callback : void user_function
(GtkWindow *window, GtkWidget *widget, gpointer user_data); |
3.2 Fonctions documentées
| void gtk_window_set_resizable (GtkWindow *window, gboolean
resizable); |
Permet de définir si l'utilisateur peut modifier
la taille de la fenêtre.
Entrée(s) :
window : la fenêtre.
resizable : TRUE si l'on peut modifier la taille, FALSE sinon.
Sortie : rien. |
| gboolean gtk_window_get_resizable (GtkWindow *window); |
Pour savoir si la taille de la fenêtre est modifiable
par l'utilisateur. Entrée(s) : window
: la fenêtre. Sortie : TRUE si elle est modifiable,
FALSE sinon. |
| void gtk_window_set_gravity (GtkWindow *window, GdkGravity
gravity); |
Permet de définir le point d'origine pour le placement
de la fenêtre. Entrée(s) : window
: la fenêtre gravity : le point d'origine. Valeurs possibles
: *GDK_GRAVITY_NORTH_WEST origine en haut à gauche
de l'écran. *GDK_GRAVITY_NORTH origine en haut
au milieu de l'écran. *GDK_GRAVITY_NORTH_EAST origine
en haut à droite de l'écran. *GDK_GRAVITY_WEST
origine au mileu à gauche de l'écran. *GDK_GRAVITY_CENTER
origine au milieu de l'écran. *GDK_GRAVITY_EAST
origine au milieu à droite de l'écran. *GDK_GRAVITY_SOUTH_WEST
origine en bas à gauche de l'écran. *GDK_GRAVITY_SOUTH
origine en bas au milieu de l'écran. *GDK_GRAVITY_SOUTH_EAST
origine en bas à droite de l'écran. *GDK_GRAVITY_STATIC
l'origine est le coin supérieur droit de la fenêtre
elle-même. Sortie : rien. |
| GdkGravity gtk_window_get_gravity (GtkWindow *window); |
Pour obtenir le point d'origine à l'ecran.
Entrée(s) : window : la fenêtre.
Sortie : GdkGravity (énumérer plus haut).
|
| void gtk_window_set_focus (GtkWindow *window, GtkWidget
*focus); |
Permet de définir le widget qui aura le focus.
Entrée(s) : window : la fenêtre
contant le widget. focus : le widget à selectionner.
Sortie : rien. |
| GtkWidget* gtk_window_get_focus (GtkWindow *window); |
Pour connaitre le widget qui a le focus. Entrée(s)
: window : la fenêtre. Sortie
:un pointeur sur le widget ayant le focus |
| void gtk_window_set_default (GtkWindow *window, GtkWidget
*default_widget); |
Pour définir le widget qui aura le focus par défaut.
Entrée(s) : window : la fenêtre
contant le widget. default_widget : le widget à selectionner.
Sortie : rien. |
| void gtk_window_iconify (GtkWindow *window); |
Permet de minimiser la fenêtre. Entrée(s)
: window : la fenêtre. Sortie
: rien. |
| void gtk_window_deiconify (GtkWindow *window); |
Pour réafficher la fenêtre lorsque celle-ci
est minimisée. Entrée(s) : window
: la fenêtre. Sortie : rien. |
| void gtk_window_maximize (GtkWindow *window); |
Permet de maximiser la fenêtre. Entrée(s)
: window : la fenêtre. Sortie
: rien. |
| void gtk_window_unmaximize (GtkWindow *window); |
Redonne une fenêtre maximisée sa taille précédente.
Entrée(s) : window : la fenêtre.
Sortie : rien. |
| void gtk_window_set_decorated (GtkWindow *window, gboolean
setting); |
Pour afficher la barre de titre de la fenêtre.
Entrée(s) : window : la fenêtre.
resizable : TRUE si l'on veux l'afficher, FALSE sinon. Sortie
: rien. |
| gboolean gtk_window_get_decorated (GtkWindow *window); |
Pour savoir si la barre de titre d'une fenêtre est
visible. Entrée(s) : window : la
fenêtre. Sortie : TRUE si elle est visible, FALSE
sinon. |
| void gtk_window_resize (GtkWindow *window, gint width,
gint height); |
Pour définir la nouvelle taille de la fenêtre.
Entrée(s) : window : la fenêtre.
width : largeur. height : hauteur. Sortie
: rien. |
3.3 Fonctions non documentées
void gtk_window_set_wmclass (GtkWindow *window, const gchar *wmclass_name, const
gchar *wmclass_class);
void gtk_window_set_policy (GtkWindow *window, gintallow_shrink, gintallow_grow,
gintauto_shrink);
void gtk_window_add_accel_group (GtkWindow *window, GtkAccelGroup *accel_group);
void gtk_window_remove_accel_group (GtkWindow *window, GtkAccelGroup *accel_group);
gboolean gtk_window_activate_focus (GtkWindow *window);
gboolean gtk_window_activate_default (GtkWindow *window);
void gtk_window_set_modal (GtkWindow *window, gboolean modal);
void gtk_window_set_geometry_hints (GtkWindow *window, GtkWidget *geometry_widget,
GdkGeometry *geometry, GdkWindowHints geom_mask);
void gtk_window_set_transient_for (GtkWindow *window, GtkWindow *parent);
void gtk_window_set_destroy_with_parent(GtkWindow *window, gboolean setting);
GList* gtk_window_list_toplevels (void);
void gtk_window_add_mnemonic (GtkWindow *window, guintkeyval, GtkWidget *target);
void gtk_window_remove_mnemonic (GtkWindow *window, guintkeyval, GtkWidget *target);
gboolean gtk_window_mnemonic_activate (GtkWindow *window, guintkeyval, GdkModifierType
modifier);
void gtk_window_present (GtkWindow *window);
void gtk_window_stick (GtkWindow *window);
void gtk_window_unstick (GtkWindow *window);
void gtk_window_begin_resize_drag (GtkWindow *window, GdkWindowEdge edge, gint
button, gintroot_x, gintroot_y, guint32 timestamp);
void gtk_window_begin_move_drag (GtkWindow *window, gintbutton, gintroot_x, gintroot_y,
guint32 timestamp);
void gtk_window_set_frame_dimensions (GtkWindow *window, gintleft, ginttop, gintright,
gintbottom);
void gtk_window_set_has_frame (GtkWindow *window, gboolean setting);
void gtk_window_set_mnemonic_modifier(GtkWindow *window, GdkModifierType modifier);
void gtk_window_set_role (GtkWindow *window, const gchar *role);
void gtk_window_set_type_hint(GtkWindow *window, GdkWindowTypeHinthint);
GList* gtk_window_get_default_icon_list(void);
gboolean gtk_window_get_destroy_with_parent(GtkWindow *window);
void gtk_window_get_frame_dimensions (GtkWindow *window, gint*left, gint*top,
gint*right, gint*bottom);
gboolean gtk_window_get_has_frame (GtkWindow *window);
GdkPixbuf* gtk_window_get_icon (GtkWindow *window);
GList* gtk_window_get_icon_list (GtkWindow *window);
GdkModifierType gtk_window_get_mnemonic_modifier(GtkWindow *window);
gboolean gtk_window_get_modal (GtkWindow *window);
G_CONST_RETURN gchar* gtk_window_get_role (GtkWindow *window);
GtkWindow* gtk_window_get_transient_for (GtkWindow *window);
GdkWindowTypeHint gtk_window_get_type_hint(GtkWindow *window);
gboolean gtk_window_parse_geometry (GtkWindow *window, const gchar *geometry);
void gtk_window_reshow_with_initial_size(GtkWindow *window);
void gtk_window_set_default_icon_list(GList *list);
void gtk_window_set_icon (GtkWindow *window, GdkPixbuf *icon);
void gtk_window_set_icon_list (GtkWindow *window, GList *list);
void gtk_decorated_window_init (GtkWindow *window);
void gtk_decorated_window_calculate_frame_size(GtkWindow *window);
void gtk_decorated_window_set_title (GtkWindow *window, const gchar *title);
void gtk_decorated_window_move_resize_window(GtkWindow *window, gintx, ginty,
gintwidth, gintheight);
Date de mise à jour : 25 novembre 2002.