Date de publication : 20 Février 2007
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.
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+ :
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
:
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.
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) gtk_init(&argc,&argv); /* Creation de la fenetre
*/ 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.
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.
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) gtk_init(&argc,&argv); /* Creation de la fenetre
*/ /* Demarrage de la boucle
evenementielle */ return EXIT_SUCCESS;
void OnDestroy(GtkWidget *pWidget, gpointer
pData) |
Résultat : |
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.".
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);
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*
.
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);
#include <stdlib.h> #include <gtk/gtk.h> void OnDestroy(GtkWidget *pWidget, gpointer pData); int main(int
argc,char **argv) gtk_init(&argc,&argv); /* Creation de la fenetre
*/ /* Connexion du signal
"destroy" */ /* Demarrage de la boucle
evenementielle */ return EXIT_SUCCESS;
void OnDestroy(GtkWidget *pWidget, gpointer
pData) |
Résultat : |
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); |
void gtk_window_set_resizable (GtkWindow *window, gboolean resizable); |
Permet de définir si l'utilisateur peut modifier
la taille de la fenêtre. |
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. |