II. Notre première fenêtre▲
II-A. Aperçu▲
II-B. Création▲
La fenêtre principale est représentée par la classe GtkWindow.
La création d'une fenêtre se fait simplement en appelant le constructeur de cette classe, la fonction gtk_window_new :
GtkWidget *
gtk_window_new (
GtkWindowType type);
Le seul paramètre de cette fonction est le type de fenêtre souhaité. Il n'y a que deux possibilités :
- GTK_WINDOW_TOPLEVEL : une fenêtre classique (c'est la base de notre application) ;
- GTK_WINDOW_POPUP : il s'agit d'une fenêtre avec seulement l'espace de travail (pas de bordure ni de menu système).
Cette fonction renvoie un pointeur sur une structure de type GtkWindow (transformé en GtkWidget grâce au polymorphisme) qui est l'entité qui va nous servir à manipuler notre fenêtre.
II-C. Affichage▲
Si vous essayez d'écrire un code maintenant, vous ne verrez rien, pourquoi ? Tout simplement parce qu'il faut préciser à GTK+ qu'il faut rendre notre fenêtre visible grâce à la fonction gtk_widget_show :
void
gtk_widget_show (
GtkWidget *
widget);
Voici le code qui permet d'afficher notre première fenêtre :
#include <stdlib.h>
#include <gtk/gtk.h>
int
main (
int
argc, char
**
argv)
{
GtkWidget *
p_window =
NULL
;
/* Initialisation de GTK+ */
gtk_init (&
argc, &
argv);
/* Creation de la fenetre principale de notre application */
p_window =
gtk_window_new (
GTK_WINDOW_TOPLEVEL);
/* Affichage de la fenetre principale */
gtk_widget_show (
p_window);
/* Lancement de la boucle principale */
gtk_main (
);
return
EXIT_SUCCESS;
}
Ceux qui se sont essayés à la création d'applications graphiques avec l'API Windows comprendront la simplicité de ce code.
II-D. Destruction▲
Dans l'exemple précédent, si vous avez essayé de terminer l'application en fermant la fenêtre (Alt+F4 ou en cliquant sur la petite croix), vous vous êtes peut-être aperçu que l'application tournait encore en fond, c'est le même problème que pour le chapitre précédent : on ne fait pas appel à gtk_main_quit. Mais comment appeler cette fonction puisque qu'une fois gtk_main appelée nous ne pouvons rien faire ? C'est là qu'intervient le mécanisme des callback. À chaque événement qui se produit, la bibliothèque GObject produit un signal, si nous souhaitons modifier le comportement par défaut du signal, il suffit de connecter notre fonction callback à l'événement souhaité :
#define g_signal_connect(instance, detailed_signal, c_handler, data);
Cette macro permet d'intercepter l'événement detailed_signal de l'objet instance grâce à la fonction c_handler qui doit être du type GCallback :
void
(*
GCallback) (
void
);
Les fonctions callback peuvent bien sûr recevoir des paramètres, mais leur nature et leur nombre dépendent du contexte, tout est géré par la bibliothèque GObject. Le prototype le plus courant pour une fonction de rappel est le suivant :
void
callback (
GtkWidget *
p_widget, gpointer *
user_data);
Dont le premier paramètre est le widget qui a reçu le signal et le second correspond au paramètre data de la fonction g_signal_connect, qui nous permet de passer des informations aux fonctions callback. Pour finir proprement notre application, il suffit d'intercepter le signal destroy de notre fenêtre et d'y assigner la fonction gtk_main_quit qui ne prend pas d'argument. Voici donc notre première application fonctionnelle :
#include <stdlib.h>
#include <gtk/gtk.h>
int
main (
int
argc, char
**
argv)
{
GtkWidget *
p_window =
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 (
gtk_main_quit), NULL
);
/* Affichage de la fenetre principale */
gtk_widget_show (
p_window);
/* Lancement de la boucle principale */
gtk_main (
);
return
EXIT_SUCCESS;
}
Il est plus courant de créer notre propre fonction de rappel pour quitter le programme; ceci permet de libérer la mémoire allouée, fermer les fichiers ouverts…
#include <stdlib.h>
#include <gtk/gtk.h>
void
cb_quit (
GtkWidget *
, gpointer);
int
main (
int
argc, char
**
argv)
{
GtkWidget *
p_window =
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
);
/* Affichage de la fenetre principale */
gtk_widget_show (
p_window);
/* Lancement de la boucle principale */
gtk_main (
);
return
EXIT_SUCCESS;
}
void
cb_quit (
GtkWidget *
p_widget, gpointer user_data)
{
gtk_main_quit
(
);
/* Parametres inutilises */
(
void
)p_widget;
(
void
)user_data;
}
Le préfixe cb_ permet de différencier les fonctions callback, qu'il est préférable de regrouper dans un ou plusieurs fichiers séparés.
À la fin de la fonction, je transtype les paramètres inutilisés pour éviter que mon compilateur m'indique des variables non utilisées, c'est le problème avec les fonctions callback, l'API nous impose un prototype.