IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours GTK 2

Date de publication : 20 Février 2007



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.