I. Introduction▲
I-A. Qu'est-ce que GTK+ ?▲
GTK+ est une bibliothèque permettant de créer des interfaces graphiques (GUI) très facilement.
À l'origine, GTK+ a été développé pour les besoins du logiciel de traitement d'images GIMP (GNU Image Manipulation Program). Mais aujourd'hui, le domaine d'application ne se limite plus seulement à GIMP, mais est utilisé dans d'autres projets. Ainsi, l'environnement GNOME (GNU Network Object Model Environment) est basé sur GTK+.
L'utilisation de GTK+ pour la création de GUI est très intéressante sur plusieurs points :
- GTK+ est sous licence GNU LGPL. Cela fait de GTK+ une bibliothèque libre, permettant ainsi de l'utiliser ou de la modifier sans aucune contrainte financière. Pour avoir plus de renseignements, le plus simple est de visiter le site du projet GNU ;
- GTK+ existe sur plusieurs plates-formes. En effet, GTK+ fonctionne sur les plates-formes UNIX-like, Windows, BeOs ;
- GTK+ est utilisable avec plusieurs langages de programmation. Même si les créateurs de GTK+ ont écrit cette bibliothèque en C, sa structure orientée objet et sa licence ont permis à d'autres développeurs d'adapter GTK+ à leur langage préféré. Ainsi, il est maintenant possible de programmer des GUI GTK+ en C, C++, Ada, Perl, Python, PHP et bien d'autres.
Les créateurs de GTK+ sont :
- ;
- ;
- .
Actuellement, GTK+ est maintenu par :
- ;
- .
Le site officiel de GTK+ est http://www.gtk.org.
I-B. Objectif du cours▲
L'objectif de ce cours est de vous offrir un support en français pour la création de vos applications GTK+ en langage C. Ce cours développera en détail la majorité des fonctions de GTK+ tout en fournissant des exemples concrets. De ce fait, ce cours sera une sorte de tutoriel couplé à un manuel de référence complet.
I-C. À qui s'adresse ce cours ?▲
Ce cours est destiné plus particulièrement à trois types de programmeurs :
- les novices en programmation GUI ;
- les personnes connaissant d'autres GUI (API Win32, wxWindow) ;
- les personnes connaissant GTK+ 1.2.
Pour profiter pleinement de ce cours, vous devez avoir une connaissance du langage C. Si tel n'est pas le cas, nous vous conseillons :
- « Le langage C, norme ANSI » de Brian W. Kernighan et Denis M. Ritchie, édition DUNOD (ISBN : 2100051164). C'est le livre de référence du langage C, écrit par ses créateurs ;
- le cours de Christian Casteyde : cours de C/C++. Il s'agit d'un très bon cours sur le C/C++. Même si ce cours est plutôt axé sur le C++, les premiers chapitres pourront vous apprendre beaucoup sur le langage C.
I-D. Organisation du cours▲
Le cours est divisé en deux parties :
- la première section est consacrée à l'étude de la GLib qui est utilisée par GTK+ ;
- la deuxième partie présentera les différents objets proposés par GTK+.
Chaque partie sera ensuite divisée en plusieurs chapitres contenant un ou plusieurs objectifs. Chaque objectif sera, la plupart du temps, accompagné d'un programme exemple qui illustrera les notions abordées.
Chaque chapitre, se terminera par la section En savoir plus, qui présente plus ou moins en détail, les fonctions et propriétés de l'objet étudié.
I-E. Comment y contribuer ?▲
Vous pouvez contribuer à ce cours tout simplement en le diffusant ou en l'améliorant (dans les termes de la licence GNU FDL jointe à la fin du cours).
Vous pouvez aussi nous informer d'une quelconque erreur de grammaire ou d'orthographe. Vous pouvez aussi nous avertir d'une mauvaise explication d'un concept, ainsi nous ferons notre possible pour faciliter la compréhension de ce cours.
Pour nous contacter, envoyez-nous un e-mail à ou alors vous pouvez laisser un message sur le forum du site https://www.developpez.com.
I-F. Auteurs de ce cours▲
Julien IBARZ
Raphaël MARINIER
Kitone
Jérome CECCHI
Hood
II. Notre premier programme▲
II-A. 1. Installation de GTK+.▲
Avant toute chose, il faut savoir que GTK+ s'appuie sur plusieurs bibliothèques et que donc, il faut absolument les installer avant de pouvoir utiliser GTK+. Voici les différentes méthodes d'installation suivant l'outil avec lequel vous travaillez.
- Sous Linux, votre distribution inclut une version de GTK+. Seules les distributions les plus récentes proposent la version 2 de GTK+. La première étape consiste donc à vérifier quelle version est installée sur votre système à l'aide de la ligne de commande suivante : 'pkg-config --modversion gtk+-2.0'. Si vous possédez déjà la version 2 de GTK+, vérifiez qu'une version plus récente que la vôtre n'existe pas sur le site officiel de GTK+. Il vous faudra donc télécharger les fichiers sources de GTK+ sur le ftp officiel : ftp://ftp.gtk.org/pub/gtk/ [ftp://ftp.gtk.org/pub/gtk/]. Il ne vous restera plus qu'à suivre les instructions d'installation fournies avec les sources qui consistent, en général, à entrer les commandes suivantes : ./configure, make et make install.
-
Sous Windows
- Avec Dev-Cpp, il suffit de télécharger les packages imagelib, GTK+ 2.0.0 runtime libraries et GTK+ 2.0.0 development package à l'adresse suivante : http://devpaks.org/category.php?category=GTK. Ensuite, l'installation de ces packages doit s'effectuer dans le même ordre que précédemment. Cette solution est, sous Windows, la plus simple et la moins chère puisque Dev-Cpp est gratuit. L'environnement de développement et le compilateur sont disponibles en téléchargement à cette adresse : http://www.bloodshed.net/dev/devcpp.html.
- Avec Visual C++, le plus rapide est de récupérer tous les fichiers nécessaires sur le site de Tor Lillqvist. Il s'occupe du portage de GTK+ sur les plates-formes Win32 et propose les fichiers nécessaires à la création et à l'exécution de programmes GTK+. Les fichiers à télécharger sont : libiconv, libintl, dirent, zlib, libpng, libjpeg, libtiff, freetype2, glib, atk, pango et gtk. La dernière étape consiste à décompresser tous les fichiers dans un répertoire de votre choix (par exemple C:\GTK) et à ajouter ce répertoire à la variable d'environnement PATH de Windows. Pour cela, il suffit d'aller dans le panneau de configuration, de cliquer sur l'icône Système. Dans la boite de dialogue, allez dans l'onglet Avancé et ajoutez le chemin et rebootez votre ordinateur.
II-B. Configuration de votre compilateur▲
Cette étape est obligatoire à la création d'un exécutable GTK+. Elle consiste surtout à configurer l'éditeur de lien et intervient à de moments différents suivants votre outil de travail :
- avec gcc, il faut rajouter l'option `pkg-config --cflags --libs gtk+-2.0` à votre ligne de compilation ;
- avec Dev-Cpp, c'est la création du projet qui est importante. Dans la boite de dialogue « New Project », sélectionner l'onglet GUI puis GTK+ et C Project ;
- avec Visual C++, il faut dans un premier temps, créer un nouveau projet Console. L'étape suivante consiste à modifier les propriétés du projet en ajoutant les librairies suivantes en entrée de l'éditeur de lien : gtk-win32-2.0.lib, gobject-2.0.lib et glib-2.0.lib.
Vous êtes maintenant prêt à créer votre première application GTK+.
II-C. 3. Créer une application GTK+▲
La première chose à faire est d'ajouter le fichier en-tête à votre code source :
#include <gtk/gtk.h>
Et ensuite, dans votre fonction main, il faut initialiser GTK+ avec cette fonction :
void
gtk_init
(
int
*
argc, char
***
argv);
Les deux paramètres à passer à cette fonction correspondent aux paramètres reçus par la fonction main. Cette fonction récupère les valeurs passées par la ligne de commande et configure GTK+. Les différentes valeurs qui sont reconnues par GTK+ sont :
- --gtk-module ;
- --g-fatal-warnings ;
- --gtk-debug ;
- --gtk-no-debug ;
- --gdk-debug ;
- --gdk-no-debug ;
- --display ;
- --sync ;
- --name ;
- --class.
Voici le code source complet de notre première application. Elle ne fait strictement rien, mais il s'agit bien d'une application GTK+ :
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc, char
**
argv)
{
/* Initialisation de GTK+ */
gtk_init
(&
argc, &
argv);
return
EXIT_SUCCESS;
}
III. 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.
III-A. 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+ :
III-A-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éclaré, 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.
III-A-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);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
/* Affichage de la fenêtre */
gtk_widget_show
(
pWindow);
/* Destruction de la fenêtre */
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.
III-A-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 interagit 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 susceptibles 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) fournit 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 intercepté 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.
III-A-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 boucle é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)
{
/* Déclaration du widget */
GtkWidget *
pWindow;
gtk_init
(&
argc,&
argv);
/* Création de la fenêtre */
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 fenêtre */
gtk_widget_show
(
pWindow);
/* Demarrage de la boucle évènementielle */
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnDestroy
(
GtkWidget *
pWidget, gpointer pData)
{
/* Arret de la boucle évènementielle */
gtk_main_quit
(
);
}
Résultat :
III-B. 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. »
III-B-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 suivante 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.
À 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êmes 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);
III-B-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*.
III-B-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);
III-B-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnDestroy
(
GtkWidget *
pWidget, gpointer pData);
int
main
(
int
argc,char
**
argv)
{
/* Déclaration du widget */
GtkWidget *
pWindow;
gtk_init
(&
argc,&
argv);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
/* Définition de la position */
gtk_window_set_position
(
GTK_WINDOW
(
pWindow), GTK_WIN_POS_CENTER);
/* Définition de la taille de la fenêtre */
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
/* Titre de la fenêtre */
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 fenêtre */
gtk_widget_show
(
pWindow);
/* Démarrage de la boucle évènementielle */
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnDestroy
(
GtkWidget *
pWidget, gpointer pData)
{
/* Arrêt de la boucle évènementielle */
gtk_main_quit
(
);
}
Résultat :
III-C. En savoir plus▲
III-C-1. Signaux▲
Prototypes fonctions callback :
-
activate-default
Sélectionnezvoid
user_function
(
GtkWindow*
window, gpointer user_data); -
activate-focus
Sélectionnezvoid
user_function
(
GtkWindow*
window, gpointer user_data); -
frame-event
Sélectionnezgboolean
user_function
(
GtkWindow*
window, GdkEvent*
event, gpointer user_data); -
keys-changed
Sélectionnezvoid
user_function
(
GtkWindow*
window, gpointer user_data); -
move-focus
Sélectionnezvoid
user_function
(
GtkWindow*
window, GtkDirectionType arg1, gpointer user_data); - set-focus
void
user_function
(
GtkWindow *
window, GtkWidget *
widget, gpointer user_data);
III-C-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 milieu à 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'écran.
Entrée(s) :
- window : la fenêtre.
Sortie GdkGravity (énuméré 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 à sélectionner.
Sortie : rien.
GtkWidget*
gtk_window_get_focus
(
GtkWindow *
window);
Pour connaître 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 à sélectionner.
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 veut 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.
III-C-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);
IV. Les labels▲
Maintenant que nous savons créer une fenêtre, nous allons créer l'incontournable « Hello World ! ». Pour cela, nous allons utiliser le widget GtkLabel qui nous permet d'afficher du texte.
IV-A. Création et affichage d'un label▲
Nous allons maintenant voir comment créer un label, et comment l'insérer dans la fenêtre principale.
IV-A-1. Création d'un label▲
On crée un pointeur vers la structure GtkWidget.
Dans un premier temps, il faut déclarer le pointeur sur l'objet GtkLabel :
GtkWidget *
pLabel;
Ensuite il faut initialiser cet objet. Pour cela, il n'existe qu'une seule fonction :
GtkWidget*
gtk_label_new
(
const
char
*
str);
Le paramètre str n'est autre que la chaîne de caractères qu'il faudra afficher.
Pour notre exemple, la ligne de code sera :
pLabel =
gtk_label_new
(
"
Hello World!
"
);
IV-A-2. Insérer le texte dans la fenêtre▲
Pour pouvoir afficher le texte, il faut insérer le widget pLabel dans la fenêtre principale (widget pWindow). Pour cela, nous allons utiliser le fait que le widget GtkWindow dérive du widget GtkContainer. L'atout principal d'un GtkContainer est, comme son nom le laisse entendre, qu'il peut contenir et afficher un autre widget. Les widgets de ce type sont appelés des conteneurs. Il faudra donc différencier deux types d'objets :
- le widget conteneur (aussi appelé widget parent) ;
- le widget contenu (aussi appelé widget enfant) qui pourra par la suite devenir lui-même un conteneur s'il possède les propriétés de GtkContainer.
Étudions donc maintenant la fonction qui nous servira à insérer un widget dans un widget conteneur :
void
gtk_container_add
(
GtkContainer *
container, GtkWidget *
widget);
Le premier paramètre, container, est le widget conteneur dans lequel on veut insérer le widget widget qui lui est passé en deuxième paramètre. Le premier paramètre de cette fonction est de type GtkContainer, alors que les widgets conteneurs seront tous de type GtkWidget. Il faudra donc à nouveau utiliser une macro de conversion qui cette fois est GTK_CONTAINER().
Pour notre exemple, la ligne de code sera :
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pLabel);
IV-A-3. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget*
pLabel;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les labels
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
/* Creation du label */
pLabel=
gtk_label_new
(
"
Hello World!
"
);
/* On ajoute le label a l'intérieur de la fenêtre */
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pLabel);
/* Affichage de la fenêtré et de tout ce qu'il contient */
gtk_widget_show_all
(
pWindow);
/* Connexion du signal
/* On appelle directement la fonction de sortie de boucle */
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return EXIT_SUCCESS;
}
Résultat :
IV-B. Les caractères accentués▲
Vous avez peut-être déjà essayé d'afficher du texte contenant des caractères tel que « é, è, à… », et lors de l'exécution, votre texte ne s'affiche complètement. Nous allons maintenant voir le pourquoi du comment.
IV-B-1. Application test▲
Pour vous montrer tout cela, nous allons reprendre l'exemple précédent en remplaçant « Hello Word » par « Texte à afficher », et cela ne marche pas! En effet vous obtenez cela :
Et en plus sur la console, vous avez le message d'erreur suivant :
** (Label2.exe) : WARNING **: Invalid UTF8 string passed to pango_layout_set_text()
IV-B-2. Comment ça marche ?▲
Pour afficher du texte, Gtk utilise la librairie Pango qui s'occupe du rendu et de l'affichage du texte. Le but de Pango est de permettre l'internationalisation des applications, et pour cela Pango utilise l'encodage UTF8. Ce charset est codée sur 16 bits, ce qui offre la possibilité d'afficher plus 65000 caractères, permettant ainsi d'afficher des caractères accentués et bien plus (ex. : pour le grec, le chinois…).
Puisque Pango sait faire tout cela, pourquoi le test n'a-t-il pas fonctionné? Et bien, tout simplement parce que votre système d'exploitation n'utilise pas ce charset. Lorsque vous souhaitez afficher « Texte à afficher », Pango va avant tout vérifier l'encodage d'un caractère et si l'un de ces caractères n'est pas correct, Pango va arrêter son processus de rendu et envoyer un message d'erreur.
Le moyen le plus simple pour voir les effets d'une erreur d'encodage est de changer celui de votre navigateur. Modifiez les options de votre navigateur afin d'utiliser l'encodage UNICODE. Cette page web utilisant le charset iso-8859-1, les caractères accentués deviendront des carrés ou autre chose.
IV-B-3. Solution▲
Une seule chose s'impose à nous : il faut convertir notre chaîne de caractères en UTF8. Pour cela, il faut utiliser une fonction de Glib qui est :
gchar*
g_locale_to_utf8
(
const
gchar *
opsysstring, gsize len, gsize *
bytes_read, gsize *
bytes_written, GError **
error);
La valeur de retour est le pointeur sur la chaîne de caractère fraîchement convertie. Si une erreur est survenue lors de la conversion, g_locale_to_utf8 renvoie NULL. Il faudra tout de même libérer le mémoire allouée par cette fonction lorsque la variable ne sera plus utile.
Le premier paramètre opsysstring est la chaîne de caractère à convertir et le second paramètre len correspond à la longueur de la chaîne. Ce paramètre sera en général égal à -1 (on laisse la bibliothèque calculer la longueur toute seule).
Les trois derniers paramètres sont utiles en cas d'erreur lors de la conversion. Tout d'abord bytes_read est le nombre d'octets qui ont été lus dans le texte à convertir, et bytes_writen le nombre d'octets qui ont été écrits dans la nouvelle chaîne de caractères.
Le dernier paramètre error, donne plus de précision en cas d'erreur. Voici la liste des messages d'erreur possibles :
- G_CONVERT_ERROR_NO_CONVERSION ;
- G_CONVERT_ERROR_ILLEGAL_SEQUENCE ;
- G_CONVERT_ERROR_FAILED ;
- G_CONVERT_ERROR_PARTIAL_INPUT ;
- G_CONVERT_ERROR_BAD_URI ;
- G_CONVERT_ERROR_NOT_ABSOLUTE_PATH.
Pour notre exemple, nous n'allons pas utiliser les trois derniers paramètres. En cas d'erreur, il n'y aura donc aucun moyen d'avoir plus de précision sur l'erreur survenue.
IV-B-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget*
pLabel;
gchar*
sUtf8;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les labels II
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
/* Creation du label avec g_locale_to_utf8 */
sUtf8 =
g_locale_to_utf8
(
"
Texte à afficher
"
, -
1
, NULL
, NULL
, NULL
);
pLabel=
gtk_label_new
(
sUtf8);
g_free
(
sUtf8);
/* On ajoute le label a l'intérieur de la fenêtre */
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pLabel);
/* Affichage de la fenêtre et de tout ce qu'il contient */
gtk_widget_show_all
(
pWindow);
/* Connexion du signal
/* On appelle directement la fonction de sortie de boucle */
g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_main();
return EXIT_SUCCESS;
}
Résultat :
IV-C. Formatage du texte▲
Nous allons maintenant voir comment modifier l'apparence de notre texte (police, couleur…).
Pour notre application test, nous allons afficher une ligne en Courier gras taille 10, une ligne en Times New Roman italique bleu taille 12, et une ligne en Verdana souligné taille 16. Et tout cela centré (bien sûr).
IV-C-1. Définition du format▲
Une fois encore, nous allons utiliser les propriétés de Pango (même si nous n'allons pas utiliser les fonctions de Pango directement).
Pour définir le format du texte, il suffit d'insérer des balises à l'intérieur même de notre texte. Pango s'occupe ensuite de rechercher les balises puis de formater le texte à notre convenance.
IV-C-2. Les balises rapides▲
Les balises rapides servent à mettre le texte en gras, italique ou autre de manière très simple. Voici l'intégralité de ces balises :
texte texte texte
Balise |
Action |
Exemple |
---|---|---|
<b> |
Met le texte en gras |
texte |
<big> |
Augment légèrement la taille du texte |
|
<i> |
Met le texte en italique |
texte |
<s> |
Barre le texte |
|
<sub> |
Met le texte en indice |
texte |
<sup> |
Met le texte en exposant |
texte |
<small> |
Diminue légèrement la taille du texte |
|
<tt> |
Met le texte en télétype |
|
<u> |
Souligne le texte |
texte |
Pour utiliser ces balises, il suffit d'encadrer le texte à modifier des balises de formatage. Par exemple, pour mettre le texte en gras, il faudra entrer : « Normal vs <b>Gras</b> ».
Mais cela ne suffit pas, il faut aussi dire que le texte utilise les balises Pango, ce qui est possible avec la fonction suivante :
void
gtk_label_set_use_markup
(
GtkLabel *
label, gboolean setting);
Il faut mettre le paramètre setting à TRUE, et le texte sera alors formaté en conséquence.
Un autre moyen de spécifier l'utilisation des balises est d'utiliser cette fonction :
void
gtk_label_set_markup
(
GtkLabel *
label, const
gchar *
str);
Cette fonction dit à Pango qu'il faut utiliser les balises, mais elle modifie aussi le label en affichant la chaîne de caractères str (deuxième paramètre).
IV-C-3. La balise <span>▲
Cette fois-ci, nous allons étudier la balise <span> en détail. Avec celle-ci, nous allons pouvoir changer la police de caractères, la couleur du texte et bien d'autres choses.
Cette balise s'utilise comme les précédentes si ce n'est qu'elle accepte des paramètres. Le tableau ci-dessous présente tous les paramètres et les effets sur le texte.
Paramètre |
Utilisation |
Exemple |
---|---|---|
font_family |
Pour définir la police à utiliser. Si la valeur donnée à ce paramètre est incorrecte, la police par défaut (Sans Serif) sera utilisée. |
|
face |
Identique à font_family |
|
size |
Pour définir la taille du texte (par défaut 10). |
|
style |
Pour définir le style du texte. Trois valeurs possibles : normal, oblique, italic. |
|
font_desc |
Permet de combiner les paramètres précédents en un seul. |
|
weight |
Permet de définir l'épaisseur des lettres. Les valeurs peuvent être ultralight, light, normal, bold, utrabold, heavy ou encore une valeur numérique. (Vous remarquerez qu'il n'y a que peu ou pas de différence). |
|
variant |
Pour définir si l'on veut du texte normal (normal) ou en petite majuscule (smallcaps). |
|
stretch |
Permet d'étirer le texte. La valeur de ce paramètre peut être : |
|
foreground |
Pour définir la couleur du texte. Il faut donner la valeur hexadécimale de la palette RVB. |
|
background |
Pour définir la couleur du fond. Il faut donner la valeur hexadécimale de la palette RVB. |
|
underline |
Pour souligner le texte. |
|
rise |
Pour déplacer le texte verticalement. |
|
strikethrough |
Pour barrer le texte. |
|
lang |
Pour indiquer la langue du texte. |
Tous ces paramètres peuvent être mis à l'intérieur d'une seule balise <span>.
IV-C-4. Alignement du texte▲
Maintenant, nous allons voir comment aligner notre texte, lorsque celui-ci comporte plusieurs lignes. Comme d'habitude, GTK+ nous fournit une fonction très simple d'utilisation :
void
gtk_label_set_justify
(
GtkLabel *
label, GtkJustification jtype);
Le paramètre jtype correspond à l'alignement du texte et peut prendre une de ces valeurs :
- GTK_JUSTIFY_LEFT pour aligner le texte à gauche (par défaut) ;
- GTK_JUSTIFY_RIGHT pour aligner le texte à droite ;
- GTK_JUSTIFY_CENTER pour centrer le texte ;
- GTK_JUSTIFY_FILL pour justifier le texte.
Au contraire, pour obtenir l'alignement du texte, la fonction est :
GtkJustification gtk_label_get_justify
(
GtkLabel *
label);
IV-C-5. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget*
pLabel;
gchar*
sUtf8;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow),"
Les labels III
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow),320
,200
);
/* Creation du label avec g_locale_to_utf8 */
pLabel=
gtk_label_new
(
NULL
);
/* On utilise les balises */
sUtf8 =
g_locale_to_utf8
(
"
<span face=
\"
Courier New
\"
><b>Courier New 10 Gras</b></span>
\n
"
"
<span font_desc=
\"
Times New Roman italic 12
\"
foreground=
\"
#0000FF
\"
>Times New Roman 12 Italique</span>
\n
"
"
<span face=
\"
Sans
\"
size=
\"
16
\"
><u>Sans 16 Souligné</u></span>
"
,
-
1
, NULL
, NULL
, NULL
);
gtk_label_set_markup
(
GTK_LABEL
(
pLabel), sUtf8);
g_free
(
sUtf8);
/* On centre le texte */
gtk_label_set_justify
(
GTK_LABEL
(
pLabel), GTK_JUSTIFY_CENTER);
/* On ajoute le label à l'intérieur de la fenêtre */
gtk_container_add
(
GTK_CONTAINER
(
pWindow),pLabel);
/* Affichage de la fenêtre et de tout ce qu'il contient */
gtk_widget_show_all
(
pWindow);
/* Connexion du signal
/* On appelle directement la fonction de sortie de boucle */
g_signal_connect(G_OBJECT(pWindow),"destroy",G_CALLBACK(gtk_main_quit),0);
gtk_main();
return EXIT_SUCCESS;
}
Résultat :
IV-D. En savoir plus▲
IV-D-1. Fonctions documentées▲
Sélectionnez
Ces deux fonctions permettent de changer le texte d'un GtkLabel.
|
Sélectionnez
Permet de recevoir l'adresse de la chaîne de caractère affichée par le label.
|
Sélectionnez
Permet de savoir si un label utilise les balises de formatages Pango.
|
IV-D-2. Fonctions non documentées▲
void
gtk_label_set_attributes
(
GtkLabel *
label, PangoAttrList *
attrs);
void
gtk_label_set_markup_with_mnemonic
(
GtkLabel *
label, const
gchar *
str);
void
gtk_label_set_pattern
(
GtkLabel *
label, const
gchar *
pattern);
guint gtk_label_parse_uline
(
GtkLabel *
label, const
gchar *
string);
void
gtk_label_set_line_wrap
(
GtkLabel *
label, gboolean wrap);
void
gtk_label_get_layout_offsets
(
GtkLabel *
label, gint *
x, gint *
y);
guint gtk_label_get_mnemonic_keyval
(
GtkLabel *
label);
gboolean gtk_label_get_selectable
(
GtkLabel *
label);
GtkWidget*
gtk_label_new_with_mnemonic
(
const
char
*
str);
void
gtk_label_select_region
(
GtkLabel *
label, gint start_offset, gint end_offset);
void
gtk_label_set_mnemonic_widget
(
GtkLabel *
label, GtkWidget *
widget);
void
gtk_label_set_selectable
(
GtkLabel *
label, gboolean setting);
void
gtk_label_set_text_with_mnemonic
(
GtkLabel *
label, const
gchar *
str);
PangoAttrList*
gtk_label_get_attributes
(
GtkLabel *
label);
PangoLayout*
gtk_label_get_layout
(
GtkLabel *
label);
gboolean gtk_label_get_line_wrap
(
GtkLabel *
label);
GtkWidget*
gtk_label_get_mnemonic_widget
(
GtkLabel *
label);
gboolean gtk_label_get_selection_bounds
(
GtkLabel *
label, gint *
start, gint *
end);
gboolean gtk_label_get_use_underline
(
GtkLabel *
label);
void
gtk_label_set_use_underline
(
GtkLabel *
label, gboolean setting);
V. Les boutons (partie 1)▲
Nous allons cette fois nous intéresser à un élément essentiel d'une interface graphique : le bouton. En effet celui-ci permet à l'utilisateur d'effectuer une action grâce à un simple clic de souris. GTK+ nous permet de les utiliser grâce au widget GtkButton :
V-A. Création et affichage d'un bouton▲
Dans ce chapitre, notre objectif sera de créer une application contenant un bouton qui permettra de quitter l'application.
V-A-1. Créer un bouton avec du texte▲
Dans un premier temps, nous allons déclarer un pointeur vers une structure GtkWidget afin de pouvoir ensuite créer le bouton.
GtkWidget *
pQuitBtn;
Ensuite, il faut initialiser le bouton. Pour cela, GTK+ permet l'utilisation de quatre fonctions différentes :
GtkWidget*
gtk_button_new
(
void
);
GtkWidget*
gtk_button_new_with_label
(
const
gchar *
label);
GtkWidget*
gtk_button_new_with_mnemonic
(
const
gchar *
label);
GtkWidget*
gtk_button_new_from_stock
(
const
gchar *
stock_id);
La première fonction permet de créer un bouton vide. Cela permet de personnaliser complètement le bouton, car GtkButton dérive de GtkContainer. On peut donc inclure n'importe quel type de widget dans le bouton (label, image…).
La deuxième fonction s'occupe en plus d'insérer un label à l'intérieur du bouton. Le paramètre label correspond au texte à afficher. Comme pour le widget GtkLabel, si un caractère accentué est utilisé, il faudra appeler la fonction g_locale_to_utf8 pour avoir un affichage correct du texte (voir IV. Les labels pour plus de précision).
La troisième fonction ajoute à cela une nouvelle fonctionnalité. Elle permet, en plus d'afficher un label, de faire réagir le bouton à l'aide d'un raccourci clavier. La touche servant de raccourci est spécifiée dans le paramètre label. Il suffit de mettre « _ » devant la lettre souhaitée pour que la combinaison Atl+Touche active le bouton. Par exemple pour l'application de ce chapitre, le texte à afficher sera « Quitter » et si nous voulons que la combinaison de touches Atl+Q permette de quitter l'application, le paramètre label devra être « _Quitter ».
La quatrième fonction permet de créer un bouton avec un label, un raccourci clavier et une image. Cependant, pour faire cela, GTK+ utilise les GtkStockItem qui sont une structure contenant les informations sur le label et l'image à afficher. GTK+ comporte déjà beaucoup de GtkStockItem prédéfinis (en tout cas les plus courants). Le paramètre stock_id est donc l'identifiant du GtkStockItem à utiliser. Pour notre exemple, l'identifiant est GTK_STOCK_QUIT.
V-A-2. Quitter l'application en cliquant sur le bouton▲
Pour cela, nous allons surveiller le signal « clicked » qui est émis lorsque l'utilisateur clique sur le bouton. Lorsque ce signal est reçu, nous allons appeler gtk_main_quit pour fermer l'application et détruire tous les widgets. La ligne de code est donc :
g_signal_connect
(
G_OBJECT
(
pQuitBtn), "
clicked
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
V-A-3. Affichage dans une fenêtre▲
Comme pour le chapitre précédent, on utilise la fonction gtk_container_add pour insérer le bouton dans la fenêtre et gtk_widget_show_all pour afficher le tout.
V-A-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
#define EXEMPLE_1 0
#define EXEMPLE_2 1
#define EXEMPLE_3 2
void
AddBtn
(
GtkWidget *
pWindow, gint iExemple);
int
main
(
int
argc, char
**
argv)
{
GtkWidget*
pWindow;
gtk_init
(&
argc, &
argv);
/* Creation de la fenetre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
,200
);
/* Connexion du signal "destroy" de la fenêtre */
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Insertion du bouton */
AddBtn
(
pWindow, EXEMPLE_1);
/* Affichage de la fenêtre */
gtk_widget_show_all
(
pWindow);
/* Demarrage de la boucle évènementielle */
gtk_main
(
);
return
EXIT_SUCCESS;
}
/*
void AddBtn(GtkWidget *pWindow, gint iExemple)
Fonction en charge d'insérer le bouton dans la fenêtre
Parametre :
- pWindow : fenetre parente
- iExemple : mode de création
EXEMPLE_1 pour un bouton label
EXEMPLE_2 pour un bouton EXEMPLE_1 + raccourci
EXEMPLE_3 pour un bouton EXEMPLE_2 + image
*/
void
AddBtn
(
GtkWidget *
pWindow, gint iExemple)
{
GtkWidget *
pQuitBtn;
switch
(
iExemple)
{
default
:
case
EXEMPLE_1:
/* Bouton avec un label */
pQuitBtn =
gtk_button_new_with_label
(
"
Quitter
"
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les boutons - Exemple 1
"
);
break
;
case
EXEMPLE_2:
/* Bouton avec un label et un raccourci */
pQuitBtn =
gtk_button_new_with_mnemonic
(
"
_Quitter
"
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les boutons - Exemple 2
"
);
break
;
case
EXEMPLE_3:
/* Bouton avec un label, un raccourci et une image */
pQuitBtn =
gtk_button_new_from_stock
(
GTK_STOCK_QUIT);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les boutons - Exemple 3
"
);
break
;
}
/* Connexion du signal "clicked" du bouton */
g_signal_connect
(
G_OBJECT
(
pQuitBtn), "
clicked
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Insertion du bouton dans la fenêtre */
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pQuitBtn);
}
Résultat :
iExemple = EXEMPLE_1
iExemple = EXEMPLE_2
iExemple = EXEMPLE_3
V-B. En savoir plus▲
V-B-1. Signaux▲
Prototypes fonctions callback :
-
activate
-
Ce signal est émis lorsque le bouton a le focus et que l'on appuie sur la touche « Enter ».
Sélectionnezvoid
user_function
(
GtkButton*
button, gpointer user_data);
-
-
enter
-
Ce signal est émis lorsque le pointeur de la souris entre dans la zone du bouton.
Sélectionnezvoid
user_function
(
GtkButton*
button, gpointer user_data);
-
-
leave
-
Ce signal est émis lorsque le pointeur de la souris quitte la zone du bouton.
Sélectionnezvoid
user_function
(
GtkButton*
button, gpointer user_data);
-
-
pressed
-
Ce signal est émis au moment où l'on appuie sur le bouton.
Sélectionnezvoid
user_function
(
GtkButton*
button, gpointer user_data);
-
-
released
- Ce signal est émis au moment où l'on relâche le bouton.
void
user_function
(
GtkButton *
button, gpointer user_data);
V-B-2. Fonctions documentées▲
void
gtk_button_pressed
(
GtkButton *
button);
Emet le signal « pressed » pour le GtkButton concerné.
Entrée(s) :
- button : le bouton.
Sortie : rien.
void
gtk_button_released
(
GtkButton *
button);
Emet le signal « released » pour le GtkButton concerné.
Entrée(s) :
- button :le bouton.
Sortie : rien.
void
gtk_button_clicked
(
GtkButton *
button);
Emet le signal « clicked » pour le GtkButton concerné.
Entrée(s) :
- button : le bouton.
Sortie : rien.
void
gtk_button_enter
(
GtkButton *
button);
Emet le signal « enter » pour le GtkButton concerné.
Entrée(s) :
- button : le bouton.
Sortie : rien.
void
gtk_button_leave
(
GtkButton *
button);
Emet le signal « leave » pour le GtkButton concerné.
Entrée(s) :
- button : le bouton.
Sortie :rien.
void
gtk_button_set_relief
(
GtkButton *
button, GtkReliefStyle newstyle);
Définit le style du bouton.
Entrée(s) :
- button : le bouton.
- newstyle : style du bouton.
-
Les différents styles sont :
- GTK_RELIEF_NORMAL (par défaut) ;
- GTK_RELIEF_HALF ;
- GTK_RELIEF_NONE.
Sortie : rien.
GtkReliefStyle gtk_button_get_relief
(
GtkButton *
button);
Récupère le style du bouton.
Entrée(s) :
- button : le bouton.
Sortie : GtkReliefStyle.
void
gtk_button_set_label
(
GtkButton *
button, const
gchar *
label);
Modifie le texte d'un bouton.
Entrée(s) :
- button : le bouton.
- label : le texte à afficher.
Sortie : rien.
G_CONST_RETURN gchar*
gtk_button_get_label
(
GtkButton *
button);
Récupère le texte d'un bouton.
Entrée(s) :
- button : le bouton.
Sortie : const gchar*.
gboolean gtk_button_get_use_stock
(
GtkButton *
button);
Pour savoir si un bouton utilise les GtkStockItem.
Entrée(s) :
- button : le bouton.
Sortie : gboolean, TRUE si le bouton utilise un GtkStockItem, FALSE sinon.
void
gtk_button_set_use_stock
(
GtkButton *
button, gboolean use_stock);
Définit si le bouton utilise un objet GtkStockItem.
Entrée(s) :
- button : le bouton.
- use_stock : TRUE pour utiliser GtkStockItem, FALSE sinon.
Sortie : rien.
gboolean gtk_button_get_use_underline
(
GtkButton *
button);
Pour savoir si un bouton utilise un raccourci clavier.
Entrée(s) :
- button : le bouton.
Sortie :gboolean, TRUE si le bouton utilise un raccourci, FALSE sinon.
void
gtk_button_set_use_underline
(
GtkButton *
button, gboolean use_underline);
Définit le bouton utilise un raccourci clavier.
Entrée(s) :
- button : le bouton.
- use_underline : TRUE pour utiliser le raccourci, FALSE sinon.
Sortie : rien.
VI. Les box▲
Vous avez sûrement dû essayer de mettre plusieurs widgets dans une fenêtre, mais sans succès. Cela est dû au fait qu'un widget de type GtkContainer ne peut contenir qu'un seul widget. La solution à ce problème est l'utilisation des widgets de type GtkBox qui permettent d'inclure plusieurs widgets à l'intérieur.
Il existe deux catégories de GtkBox :
- Les GtkHBox qui permettent de disposer les widgets horizontalement ;
- Les GtkVBox pour les disposer verticalement.
VI-A. Utilisation des GtkBox▲
VI-A-1. Création▲
Comme toujours, la création de ces widgets est très simple. Les fonctions suivantes permettent de créer respectivement une GtkHBox et une GtkVBox :
GtkWidget*
gtk_hbox_new
(
gboolean homogeneous, gint spacing);
GtkWidget*
gtk_vbox_new
(
gboolean homogeneous, gint spacing);
Le paramètre homogeneous définit si tous les widgets contenus dans la GtkBox utilisent un espace équivalent. C'est-à-dire que si ce paramètre est à TRUE, la zone d'affichage de la GtkBox sera divisée en x zone(s) de taille égale (x étant le nombre de widgets contenus).
Le paramètre spacing permet de définir l'espacement entre chacun des widgets contenus.
VI-A-2. Insertion d'un widget▲
Les widgets GtkHBox et GtkVBox n'ont pas de fonctions spécifiques pour l'ajout de widget. Il faut, pour cela, utiliser les fonctions de GtkBox dont dérivent les différents types de box. Les fonctions les plus couramment utilisées sont :
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);
La première fonction insère les widgets de haut en bas (pour les GtkVBox) ou de gauche à droite (pour les GtkHBox). La seconde fonction fait exactement le contraire, c'est-à-dire, de bas en haut pour les GtkVBox et de droite à gauche pour les GtkHBox.
Le paramètre box est bien entendu la GtkBox dans laquelle on veut insérer le widget child (2e paramètre).
Le paramètre expand n'est utile que si la GtkBox en question n'est pas définie comme homogène (homogeneous=FALSE lors de la création). Dans ce cas, tous les widgets qui auront été insérés avec la valeur expand=TRUE se partageront tout l'espace libre de la GtkBox (les widgets avec expand=FALSE n'utiliseront que l'espace qui leur est nécessaire).
Le paramètre fill permet de définir si le widget enfant occupe toute la zone qui lui est réservée.
Et enfin, le paramètre padding permet d'ajouter de l'espace autour du widget (en plus de celui défini par le paramètre spacing lors de la création de la GtkBox).
Pour vous montrer les effets des différents paramètres, voici un tableau avec des captures d'écran avec différentes configurations :
Paramètres |
Captures |
---|---|
GtkVBox : |
|
GtkVBox : |
|
GtkVBox : |
|
GtkVBox : |
|
GtkVBox : |
|
VI-A-3. Exemple▲
Pour montrer les possibilités qu'offrent les GtkBox, nous allons créer une fenêtre contenant quatre boutons organisés comme cela :
Maintenant, la question est de savoir comment organiser les différentes GtkBox pour avoir ce résultat. C'est très simple, nous avons besoin de deux GtkBox, la première verticale, la deuxième horizontale. Voici une image qui vous explique comment nous devons organiser nos deux GtkBox :
Ici, en rouge c'est la GtkVBox qui est directement ajoutée à la fenêtre principale. On va y empiler les widgets de haut en bas avec la fonction gtk_box_pack_start. On va tout d'abord placer le « Bouton 1 », ensuite pour pouvoir ajouter les autres boutons de gauche à droite, il faut ajouter la GtkHBox (en bleu), car on ne peut pas le faire avec la GtkVBox puisqu'elle est verticale. On ajoute donc ensuite « Bouton 2 » et « Bouton 3 » dans la GtkHBox, et pour finir, on ajoute « Bouton 4 » dans la GtkVBox.
Voilà, une fois que l'on a compris comment organiser les choses, on peut tout faire.
VI-A-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pHBox;
GtkWidget *
pButton[4
];
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les GtkBox
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Création de la GtkBox verticale */
pVBox =
gtk_vbox_new
(
TRUE, 0
);
/* Ajout de la GtkVBox dans la fenêtre */
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Creation des boutons */
pButton[0
] =
gtk_button_new_with_label
(
"
Bouton 1
"
);
pButton[1
] =
gtk_button_new_with_label
(
"
Bouton 2
"
);
pButton[2
] =
gtk_button_new_with_label
(
"
Bouton 3
"
);
pButton[3
] =
gtk_button_new_with_label
(
"
Bouton 4
"
);
/* Ajout de Bouton 1 dans la GtkVBox */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton[0
], TRUE, FALSE, 0
);
/* Création de la box horizontale */
pHBox =
gtk_hbox_new
(
TRUE, 0
);
/* Ajout de la GtkHBox dans la GtkVBox */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pHBox, TRUE, TRUE, 0
);
/* Ajout des boutons 2 et 3 dans la GtkHBox */
gtk_box_pack_start
(
GTK_BOX
(
pHBox), pButton[1
], TRUE, TRUE, 0
);
gtk_box_pack_start
(
GTK_BOX
(
pHBox), pButton[2
], TRUE, FALSE, 0
);
/* Ajout du dernier bouton dans la GtkVBox */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton[3
], TRUE, TRUE, 0
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
VI-B. En savoir plus▲
VI-B-1. Fonctions documentées▲
gboolean gtk_box_get_homogeneous
(
GtkBox *
box);
Utilisée pour savoir si une GtkBox est homogène.
Entrée(s) :
- box : la GtkBox.
Sortie : TRUE si box est homogène, FALSE sinon.
void
gtk_box_set_homogeneous
(
GtkBox *
box, gboolean homogeneous);
Utilisée pour définir si une GtkBox est homogène ou pas.
Entrée(s) :
- box : la GtkBox.
- homogeneous : TRUE si l'on veut que box soit homogène, FALSE sinon.
Sortie : rien.
gint gtk_box_get_spacing
(
GtkBox *
box);
Utilisée pour connaître l'espace entre les widgets d'une GtkBox.
Entrée(s) :
- box : la GtkBox.
Sortie : gint.
void
gtk_box_set_spacing
(
GtkBox *
box, gint spacing);
Utilisée pour définir l'espacement entre les widgets.
Entrée(s) :
- box : la GtkBox.
- spacing : espace entre les widgets.
Sortie : rien.
VI-B-2. Fonctions non documentées▲
void
gtk_box_pack_start_defaults
(
GtkBox *
box, GtkWidget *
widget);
void
gtk_box_pack_end_defaults
(
GtkBox *
box, GtkWidget *
widget);
void
gtk_box_reorder_child
(
GtkBox *
box, GtkWidget *
child, gint position);
void
gtk_box_query_child_packing
(
GtkBox *
box, GtkWidget *
child, gboolean *
expand, gboolean *
fill, guint *
padding, GtkPackType *
pack_type);
void
gtk_box_set_child_packing
(
GtkBox *
box, GtkWidget *
child, gboolean expand, gboolean fill, guint padding, GtkPackType pack_type);
VII. Les tables▲
Dans la famille des containers, voilà sûrement le widget le plus intéressant. En effet il peut être parfois douloureux de placer correctement son interface avec l'utilisation de plusieurs GtkBox. Le widget GtkTable est conçu pour résoudre ce problème, car il utilise une grille invisible pour attacher les widgets, mais sans pour autant perdre la puissance de GTK+ avec le redimensionnement automatique.
VII-A. Introduction▲
Au moment de la création de la GtkTable, nous allons spécifier le nombre de lignes et de colonnes, puis y placer les éléments avec trois principales caractéristiques :
- la position de départ et de fin de l'élément par rapport aux lignes ;
- la position de départ et fin de l'élément par rapport aux colonnes ;
- la façon de réagir du widget (remplir la zone, agrandir, etc.).
Reprenons l'exemple que nous avons créé dans le chapitre précédent sur les GtkBox. Nous avons créé une fenêtre contenant quatre boutons :
Pour faire cela sans GtkTable, nous avons dû créer deux GtkBox, une première verticale, puis une deuxième horizontale dans laquelle nous avons placé les boutons 2 et 3, puis ajouter le quatrième bouton dans la première GtkBox (verticale), voilà beaucoup de travail pour pas grand-chose.
Avec le widget GtkTable, la première chose à faire sera de choisir le nombre de lignes et de colonnes sur cette grille. Dans notre cas, il s'agit d'une grille à trois lignes et deux colonnes :
Ensuite il suffit de placer nos boutons sur cette grille, en spécifiant en premier les points de départ et d'arrivée suivant les colonnes puis suivant les lignes :
- Bouton 1 : de 0 à 2 suivant les colonnes et de 0 à 1 suivant les lignes -> (0, 2, 0, 1) ;
- Bouton 2 : de 0 à 1 suivant les colonnes et de 1 à 2 suivant les lignes -> (0, 1, 1, 2) ;
- Bouton 3 : de 1 à 2 suivant les colonnes et de 1 à 2 suivant les lignes -> (1, 2, 1, 2) ;
- Bouton 4 : de 0 à 2 suivant les colonnes et de 2 à 3 suivant les lignes -> (0, 2, 2, 3).
Comme vous pouvez le constater, on ne donne pas la longueur et la largeur du widget, mais sa position finale sur la grille. Cela devient nettement plus facile et naturel de positionner les widgets sur une grille, car si ici nous ne gagnons que deux opérations par rapport à la méthode GtkBox, cette valeur s'élève très vite quand il s'agit de placer plus de 4 boutons. Après ces quelques explications, voyons comment programmer cela.
VII-B. Utilisation du widget GtkTable▲
VII-B-1. Création▲
La fonction de création est :
GtkWidget*
gtk_table_new
(
guint rows, guint columns, gboolean homogeneous);
Les paramètres rows et columns permettent de définir respectivement le nombre de lignes et de colonnes de la grille. Le paramètre homogeneous quant à lui définit, comme pour une GtkBox, si tous les widgets contenus dans la GtkTable utilisent un espace équivalent.
VII-B-2. Insertion de widget▲
La première fonction étudiée est :
void
gtk_table_attach
(
GtkTable *
table, GtkWidget *
child,
guint left_attach, guint right_attach,
guint top_attach, guint bottom_attach,
GtkAttachOptions xoptions, GtkAttachOptions yoptions,
guint xpadding, guint ypadding);
À première vue, cette fonction peut apparaître compliquée, mais elle est en réalité très simple. Le paramètre child représente le widget à attacher à la grille, les paramètres left_attach et right_attach, les positions à gauche et à droite du widget et les paramètres top_attach et bottom_attach, les positions supérieures et inférieures du widget.
Les paramètres xoptions et yoptions permettent de spécifier respectivement la façon dont le widget réagit horizontalement et verticalement au redimensionnement de la GtkTable. Ces paramètres peuvent prendre trois valeurs (que l'on peut associer) :
- GTK_EXPAND : spécifie que cette section de la grille s'étirera pour remplir l'espace disponible ;
- GTK_SHRINK : détermine ce qui se produira s'il y a un espace insuffisant pour répondre à la requête de taille du widget enfant, alors le widget se voit attribuer une allocation réduite, ce qui peut entraîner un effet de « bords coupés » ;
- GTK_FILL : spécifie que le widget enfant s'étirera pour remplir l'espace disponible, important que si GTK_EXPAND est défini.
Les deux derniers paramètres xpadding et ypadding définissent l'espace supplémentaire à ajouter aux bords du widget (à droite et à gauche pour le premier, au-dessus et en dessous pour le second).
Regardons maintenant les effets des paramètres xoptions et yoptions suivant différentes valeurs :
Valeurs de xoptions et yoptions |
Résultat |
---|---|
xoptions = GTK_EXPAND |
|
xoptions = GTK_EXPAND | GTK_FILL |
|
xoptions = GTK_EXPAND |
|
xoptions = GTK_EXPAND | GTK_FILL |
|
La deuxième fonction est :
void
gtk_table_attach_defaults
(
GtkTable *
table, GtkWidget *
child,
guint left_attach, guint right_attach,
guint top_attach, guint bottom_attach );
Ceci est la version simplifiée de la première fonction, car elle définit automatiquement les paramètres xoptions et yoptions à GTK_EXPAND | GTK_FILL et les paramètres xpadding et ypadding à 0.
VII-B-3. Modifier la table▲
Il est possible de changer la taille de la grille après sa création à l'aide de cette fonction :
void
gtk_table_resize
(
GtkTable *
table, guint rows, guint columns);
Le paramètre table est la GtkTable à modifier, et les paramètres rows et columns les nouveaux nombres de lignes et de colonnes.
Ces deux fonctions permettent de changer l'espace d'une ligne ou d'une colonne spécifique :
gtk_table_set_row_spacing
(
GtkTable *
table, guint row, guint spacing);
gtk_table_set_col_spacing
(
GtkTable *
table, guint column, guint spacing);
La première définit l'espace autour d'une ligne tandis que la deuxième fait la même chose pour une colonne.
Celles-ci ont le même rôle que les deux précédentes fonctions, mais agissent sur l'ensemble de la GtkTable :
gtk_table_set_row_spacings
(
GtkTable *
table, guint spacing);
gtk_table_set_col_spacings
(
GtkTable *
table, guint spacing);
Et pour connaître ces espacements, nous avons quatre fonctions différentes :
guint gtk_table_get_row_spacing
(
GtkTable *
table, guint row);
guint gtk_table_get_col_spacing
(
GtkTable *
table, guint column);
guint gtk_table_get_default_row_spacing
(
GtkTable *
table);
guint gtk_table_get_default_col_spacing
(
GtkTable *
table);
Les deux premières fonctions permettent de connaître l'espace entre lignes numéro row (ou la colonne numéro column) et sa suivante. Les deux autres fonctions quant à elles, renvoient la valeur par défaut des espacements, c'est-à-dire la valeur qui sera utilisée au prochain ajout d'un widget.
VII-B-4. Exemple▲
Nous allons utiliser le même exemple que dans le chapitre sur les GtkBox, pour bien montrer la différence au niveau du code.
VII-B-5. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pTable;
GtkWidget *
pButton[4
];
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les GtkTable
"
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Creation et insertion de la table 3 lignes 2 colonnes */
pTable=
gtk_table_new
(
3
,2
,TRUE);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), GTK_WIDGET
(
pTable));
/* Creation des boutons */
pButton[0
]=
gtk_button_new_with_label
(
"
Bouton 1
"
);
pButton[1
]=
gtk_button_new_with_label
(
"
Bouton 2
"
);
pButton[2
]=
gtk_button_new_with_label
(
"
Bouton 3
"
);
pButton[3
]=
gtk_button_new_with_label
(
"
Bouton 4
"
);
/* Insertion des boutons */
gtk_table_attach
(
GTK_TABLE
(
pTable), pButton[0
],
0
, 2
, 0
, 1
,
GTK_EXPAND |
GTK_FILL, GTK_EXPAND,
0
, 0
);
gtk_table_attach_defaults
(
GTK_TABLE
(
pTable), pButton[1
],
0
, 1
, 1
, 2
);
gtk_table_attach
(
GTK_TABLE
(
pTable), pButton[2
],
1
, 2
, 1
, 2
,
GTK_EXPAND, GTK_EXPAND |
GTK_FILL,
0
, 0
);
gtk_table_attach_defaults
(
GTK_TABLE
(
pTable), pButton[3
],
0
, 2
, 2
, 3
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
VII-C. En savoir plus▲
VII-C-1. Fonctions documentées▲
void
gtk_table_set_homogeneous
(
GtkTable *
table, gboolean homogeneous );
Permet de définir si la table est homogène ou pas.
Entrée(s) :
- table : la GtkTable.
- homogeneous : TRUE si l'on veut que table soit homogène, FALSE sinon.
Sortie : rien.
gboolean gtk_table_get_homogeneous
(
GtkTable *
table);
Permet de savoir si la table est homogène.
Entrée(s) :
- table : la GtkTable.
Sortie : TRUE si table est homogène, FALSE sinon.
VIII. Les listes chaînées▲
Vous connaissez sûrement déjà les listes chaînées. Elles sont très pratiques, mais il faut s'occuper soit même de la gestion de la mémoire, de chaîner les éléments, à chaque fois que l'on veut ajouter ou supprimer un élément. La bibliothèque GLib propose des listes chaînées génériques que nous allons pouvoir utiliser dans nos applications Gtk+.
VIII-A. Les listes chaînées simples : GSList▲
Regardons tout d'abord comment est défini cet objet :
struct
GSList
{
gpointer data;
struct
GSList *
next;
}
;
Nous voyons donc qu'elle nous permet de créer la plus simple des listes chaînées, c'est-à-dire que chaque élément connaît son suivant et rien d'autre. La liste s'organise suivant ce schéma :
Étudions comment créer une telle liste.
VIII-A-1. Création d'une GSList▲
Il faut d'abord avoir le pointeur sur le premier élément de la liste. Pour cela, rien de plus simple :
GSList *
premier =
NULL
;
Ensuite, il n'existe pas de fonction spécifique pour créer la liste, il suffit d'ajouter un élément à la liste. Plusieurs fonctions sont disponibles, mais nous allons en étudier deux.
GSList*
g_slist_append
(
GSList *
list, gpointer data);
GSList*
g_slist_prepend
(
GSList *
list, gpointer data);
La première g_slist_append ajoute un nouvel élément à la fin de la liste, alors que g_slist_prepend l'ajoute au début de la liste. La variable list est bien sûr la liste chaînée à laquelle on veut ajouter un élément comportant la donnée data. Il suffit de faire un cast pour donner le type de data. Si l'on veut que notre premier élément soit un widget, il suffira d'écrire la ligne de code suivante :
premier =
g_slist_append
(
premier,(
GtkWidget*
) widget);
La valeur de retour est très importante : elle correspond à l'adresse du premier élément de la liste. En effet, au départ notre élément premier ne pointe nulle part (premier = NULL), il faut donc toujours récupérer cette adresse (surtout dans le cas de g_slist_prepend où le premier élément change).
VIII-A-2. Récupérer les données d'une GSList▲
Là aussi, nous n'allons étudier que deux fonctions :
GSList*
g_slist_nth
(
GSList *
list, guint n);
gpointer g_slist_nth_data
(
GSList *
list, guint n);
List est bien sûr la liste à laquelle l'élément recherché appartient, et n est la position de l'élément dans la liste (le premier élément est à n=0). Avec ces deux fonctions, il suffit de connaître la position d'un élément pour récupérer la donnée qu'il contient.
La première fonction renvoie un pointeur sur une variable du type GSList. Il faudra donc utiliser l'opérateur -> pour récupérer la valeur data. La deuxième, par contre, renvoie directement la valeur de data.
Si la valeur donnée à n ne fait pas partie de la liste, la valeur de retour sera NULL.
Supposons qu'une variable de type GtkWidget soit stockée dans le premier élément d'une liste nommé liste, et que l'on veuille récupérer ce widget, il faudra alors coder :
temp_list =
g_slist_nth
(
liste, 0
);
widget =
(
GtkWidget*
) (
temp_list->
data);
Ou
widget =
(
GtkWidget*
) g_slist_nth_data
(
liste, 0
);
VIII-A-3. Suppression d'élément d'un GSList▲
Pour supprimer un élément définitivement d'une liste, la fonction à utiliser est la suivante :
GSList*
g_slist_remove
(
GSList *
list, gconstpointer data);
Cette fonction cherche le premier élément de la liste contenant la donnée data et le supprime. La valeur de retour est là aussi très importante, car elle correspond (toujours pareil) au nouveau premier élément de la liste. Si par hasard, plusieurs éléments contiennent la donnée data, seul le premier sera supprimé. Dans ce cas, pour tous les supprimer, il faut utiliser cette fonction (dont l'utilisation est identique à la première) :
GSList*
g_slist_remove_all
(
GSList *
list, gconstpointer data);
Pour supprimer une liste entière, la fonction est :
void
g_slist_free
(
GSList *
list);
Avec toutes ces fonctions, nous en savons suffisamment pour pouvoir utiliser une liste simple.
VIII-B. Les listes chaînées double : GList▲
Cette liste est légèrement différente, car en plus de connaître son suivant, chaque élément connaît aussi l'élément qui le précède. Cette structure est définie ainsi :
struct
GList
{
gpointer data;
struct
GList *
next;
struct
GList *
prev;
}
;
Cette nouvelle liste s'organise donc ainsi :
L'étude sera cette fois beaucoup plus rapide, car vous allez le voir, les fonctions pour les GList sont quasiment identiques à celles de GSList.
VIII-B-1. Création d'une GList▲
Là encore, il nous faut un pointeur sur le premier élément de la liste.
GList *
premier =
NULL
;
Comme pour les GList, il n'y a pas de fonction spécifique, il suffit d'ajouter des éléments avec les fonctions suivantes :
GList*
g_list_append
(
GList *
list, gpointer data);
GList*
g_list_prepend
(
GList *
list, gpointer data);
Les paramètres sont identiques que pour son homologue GSList et la valeur de retour est toujours un pointeur sur le premier élément de la liste.
VIII-B-2. Récupérer les données d'une GList▲
Une nouvelle fois, les fonctions ressemblent à celles des GSList :
GList*
g_list_nth
(
GList *
list, guint n);
gpointer g_list_nth_data
(
Glist *
list, guint n);
VIII-B-3. Suppression d'élément d'un GSList▲
Les fonctions de suppression sont toujours semblables :
GList*
g_list_remove
(
GList *
list, gconstpointer data);
GList*
g_list_remove_all
(
GList *
list, gconstpointer data);
void
g_list_free
(
GList *
list);
Bien sûr pour ces deux types de listes, d'autres fonctions existent pour ajouter, déplacer, ordonner, supprimer des éléments. Ces dernières sont (comme à l'accoutumée) dans la section en savoir plus.
Il n'y aura pas dans ce chapitre d'exemple d'utilisation, mais vous pourrez voir l'intérêt particulier de ces deux types de listes dans les chapitres suivants.
VIII-C. En savoir plus▲
VIII-C-1. Fonctions documentées▲
GSList*
g_slist_insert
(
GSList *
list, gpointer data, gint position);
GList*
g_list_insert
(
GList *
list, gpointer data, gint position);
Ajoute un nouvel élément dans une liste à la position demandée.
Entrée(s) :
- list : la liste.
- data : la valeur à ajouter.
- position : la position à laquelle sera ajouté l'élément. Si cette valeur est invalide (négative ou trop grande) l'élément sera ajouté à la fin de la liste.
Sortie : le pointeur sur le premier élément de la liste.
GSList*
g_slist_insert_before
(
GSList *
list, GSList *
sibling, gpointer data);
GList*
g_list_insert_before
(
GList *
list, GList *
sibling, gpointer data);
Ajoute un nouvel élément avant un autre élément.
Entrée(s) :
- list : la liste.
- sibling : élément avant lequel doit être insérée notre nouvelle valeur.
- data : valeur à ajouter.
Sortie : le pointeur sur le premier élément de la liste.
GSList*
g_slist_remove_link
(
GSList *
list, GSList *
link);
GList*
g_list_remove_link
(
GList *
list, GList *
link);
Supprime un élément d'une liste. L'élément supprimé deviendra le premier d'une nouvelle liste.
Entrée(s) :
- list : la liste.
- link : l'élément à supprimer de la liste.
Sortie : le pointeur sur le premier élément de la liste.
GSList*
g_slist_delete_link
(
GSList *
list, GSList *
link);
GList*
g_list_delete_link
(
GList *
list, GList *
link);
Supprime un élément d'une liste.
Entrée(s) :
- list : la liste.
- link : l'élément à supprimer.
Sortie :le pointeur sur le premier élément de la liste.
guint g_slist_length
(
GSList *
list);
guint g_list_length
(
GList *
list);
Pour connaître le nombre d'éléments d'un liste.
Entrée(s) :
- list : la liste.
Sortie : le nombre d'éléments de la liste.
GSList*
g_slist_copy
(
GSList *
list);
GList*
g_list_copy
(
GList *
list);
Crée une copie d'une liste.
Entrée(s) :
- list : la liste.
Sortie : le pointeur sur le premier élément de la nouvelle liste.
GSList*
g_slist_reverse
(
GSList *
list);
GList*
g_list_reverse
(
GList *
list);
Inverse les éléments d'une liste
Entrée(s) :
- list : la liste.
Sortie : le pointeur sur le premier élément de la liste.
GSList*
g_slist_concat
(
GSList *
list1, GSList *
list2);
GList*
g_list_concat
(
GList *
list1, GList *
list2);
Ajoute une liste à la fin d'une autre.
Entrée(s) :
- list1 : la liste de départ.
- list2 : liste à ajouter à la suite de list1.
Sortie : le pointeur sur le premier élément de la liste.
GList*
g_list_first
(
GList *
list);
Pour récupérer le premier élément d'une liste.
Entrée(s) :
- list : la liste.
Sortie : le pointeur sur le premier élément de la liste.
GSList*
g_slist_last
(
GSList *
list);
GList*
g_list_last
(
GList *
list);
Pour récupérer le dernier élément d'une liste.
Entrée(s) :
- list : la liste.
Sortie : le pointeur sur le dernier élément de la liste.
g_slist_next
(
list)
g_list_next
(
list)
Une macro permettant d'obtenir l'élément suivant d'une liste.
Entrée(s) :
- list : la liste.
Sortie : le pointeur sur l'élément suivant ou NULL si l'on est en fin de liste.
g_list_previous
(
list)
Une macro permettant d'obtenir l'élément précédent d'une liste.
Entrée(s) :
- list : la liste.
Sortie : un pointeur sur l'élément précédent ou NULL si on est en début de liste.
GSList*
g_slist_find
(
GSList *
list, gconstpointer data);
GList*
g_list_find
(
GList *
list, gconstpointer data);
Récupère l'élément contenant une certaine donnée.
Entrée(s) :
- list : la liste.
- data : la donnée à chercher.
Sortie : un pointeur sur l'élément trouvé ou NULL s'il n'y en a pas.
gint g_slist_position
(
GSList *
list, GSList *
llink);
gint g_list_position
(
GList *
list, GList *
llink);
Pour connaître la position d'un élément.
Entrée(s) :
- list : la liste.
- llink : l'élément à chercher.
Sortie : la position de l'élément dans la liste ou -1 s'il n'existe pas.
gint g_slist_index
(
GSList *
list, gconstpointer data);
gint g_list_index
(
GList *
list, gconstpointer data);
Pour connaître la position d'un élément contenant une certaine donnée.
Entrée(s) :
- list : la liste.
- data : la donnée à chercher.
Sortie : la position de l'élément dans la liste ou -1 s'il n'existe pas.
IX. Les entrées de saisie▲
Vous pouvez à présent faire interagir l'utilisateur avec des boutons, mais il peut aussi être utile de lui faire saisir des données. Nous allons utiliser pour cela le widget GtkEntry qui définit une zone de texte (une ligne) dans lequel l'utilisateur peut taper du texte ou alors dans lequel le programme peut afficher une information.
IX-A. Création et utilisation d'un GtkEntry▲
IX-A-1. 1.1 Création▲
Pour créer un GtkEntry, nous avons à notre disposition deux fonctions différentes :
GtkWidget*
gtk_entry_new
(
void
);
GtkWidget*
gtk_entry_new_with_max_length
(
gint max);
La première fonction crée un widget GtkEntry de base, tandis que la seconde permet en plus de définir le nombre maximum de caractères que l'utilisateur peut taper (paramètre max de type gint).
IX-A-2. 1.2 Utilisation▲
Nous allons maintenant comment utiliser les deux fonctions principales de ce widget.
void
gtk_entry_set_text
(
GtkEntry *
entry, const
gchar *
text);
G_CONST_RETURN gchar*
gtk_entry_get_text
(
GtkEntry *
entry);
La première fonction nous permet d'insérer du texte dans le GtkEntry. Le paramètre entry correspond bien sur au GtkEntry dans lequel on veut insérer le texte text. À noter, que cette fonction nécessite que entry soit de type GtkEntry*, il faudra donc utiliser la macro de conversion GTK_ENTRY().
La deuxième fonction permet de récupérer le texte qui a été tapé par l'utilisateur dans le GtkEntry entry. La valeur de retour est de type G_CONST_RETURN gchar*, c'est-à-dire qu'il faudra récupérer le texte dans une variable de type const gchar*. De plus, il est inutile d'allouer de la mémoire pour la variable qui va recevoir le texte, et donc de ne surtout pas libérer la mémoire, car cela rendrait votre application instable.
IX-A-3. 1.3 Exemple▲
Comme exemple, nous allons créer une fenêtre comportant un GtkEntry, un GtkButton et un GtkLabel. Le but sera d'afficher le texte du GtkEntry dans le GtkLabel. Cette opération s'effectuera lorsque l'utilisateur appuie sur la touche ENTRÉE à la fin de sa saisie (interception du signal « activate ») ou lorsqu'il cliquera sur le GtkButton (interception du signal « clicked »).
Ensuite, les fonctions callback récupèreront le texte du GtkEntry pour l'afficher dans le GtkLabel. Si cette opération ne pose aucun problème pour le signal « activate » du GtkEntry, un problème existe lorsque l'on clique sur le GtkButton.
En effet, pour faire son travail correctement, la fonction callback doit connaître le GtkEntry et le GtkLabel. Dans le cas du signal « activate », le GtkEntry est envoyé en paramètre principal de la fonction callback (widget émetteur du signal) et l'on rajoute le GtkLabel en paramètre supplémentaire. Par contre, pour le signal « clicked », le widget émetteur est le GtkButton et l'on ne pourra passer qu'un seul widget en donnée supplémentaire.
La solution consiste à utiliser les listes du chapitre précédent (VII. Les listes chaînéesLes listes chaînées) ainsi qu'une fonction du widget GtkContainer :
GList*
gtk_container_get_children
(
GtkContainer *
container);
Cette fonction crée une liste doublement chaînée contenant tous les widgets qui ont été insérés dans le widget container. Dans notre cas, il nous suffira de passer la GtkBox contenant tous les widgets à la fonction callback pour avoir accès à tout ce dont nous avons besoin.
IX-A-4. 1.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
on_activate_entry
(
GtkWidget *
pEntry, gpointer data);
void
on_copier_button
(
GtkWidget *
pButton, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pEntry;
GtkWidget *
pButton;
GtkWidget *
pLabel;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Le widget GtkEntry
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Creation du GtkEntry */
pEntry =
gtk_entry_new
(
);
/* Insertion du GtkEntry dans la GtkVBox */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pEntry, TRUE, FALSE, 0
);
pButton =
gtk_button_new_with_label
(
"
Copier
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
NULL
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pLabel, TRUE, FALSE, 0
);
/* Connexion du signal "activate" du GtkEntry */
g_signal_connect
(
G_OBJECT
(
pEntry), "
activate
"
, G_CALLBACK
(
on_activate_entry), (
GtkWidget*
) pLabel);
/* Connexion du signal "clicked" du GtkButton */
/* La donnée supplémentaire est la GtkVBox pVBox */
g_signal_connect
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
on_copier_button), (
GtkWidget*
) pVBox);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
/* Fonction callback execute lors du signal "activate" */
void
on_activate_entry
(
GtkWidget *
pEntry, gpointer data)
{
const
gchar *
sText;
/* Recuperation du texte contenu dans le GtkEntry */
sText =
gtk_entry_get_text
(
GTK_ENTRY
(
pEntry));
/* Modification du texte contenu dans le GtkLabel */
gtk_label_set_text
(
GTK_LABEL
((
GtkWidget*
)data), sText);
}
/* Fonction callback executee lors du signal "clicked" */
void
on_copier_button
(
GtkWidget *
pButton, gpointer data)
{
GtkWidget *
pTempEntry;
GtkWidget *
pTempLabel;
GList *
pList;
const
gchar *
sText;
/* Récupération de la liste des éléments que contient la GtkVBox */
pList =
gtk_container_get_children
(
GTK_CONTAINER
((
GtkWidget*
)data));
/* Le premier élément est le GtkEntry */
pTempEntry =
GTK_WIDGET
(
pList->
data);
/* Passage à l élément suivant : le GtkButton */
pList =
g_list_next
(
pList);
/* Passage à l élément suivant : le GtkLabel */
pList =
g_list_next
(
pList);
/* Cet élément est le GtkLabel */
pTempLabel =
GTK_WIDGET
(
pList->
data);
/* Recuperation du texte contenu dans le GtkEntry */
sText =
gtk_entry_get_text
(
GTK_ENTRY
(
pTempEntry));
/* Modification du texte contenu dans le GtkLabel */
gtk_label_set_text
(
GTK_LABEL
(
pTempLabel), sText);
/* Libération de la mémoire utilisée par la liste */
g_list_free
(
pList);
}
Résultat :
IX-B. Saisie d'un mot de passe▲
IX-B-1. La visibilité du texte▲
Généralement, lorsque nous tapons un mot de passe, nous souhaitons que celui-ci reste secret. Le widget GtkEntry permet cela grâce à cette fonction :
void
gtk_entry_set_visibility
(
GtkEntry *
entry, gboolean visible);
Il suffit donc de mettre le paramètre visible à FALSE pour cacher le texte qui sera entré.
À l'inverse, pour savoir si le texte entré sera visible ou pas, il faut utiliser cette fonction :
gboolean gtk_entry_get_visibility
(
GtkEntry *
entry);
La valeur de retour sera, bien sûr, égale à TRUE si le texte est visible et à FALSE dans le cas contraire.
IX-B-2. 2.2 Le caractère affiché▲
Par défaut, lorsque l'on ajoute du texte à un GtkEntry qui a son paramètre visible à FALSE, GTK+ remplacera toutes les lettres par des '*'. Pour modifier celui-ci, il faut utiliser cette fonction :
void
gtk_entry_set_invisible_char
(
GtkEntry *
entry, gunichar ch);
Le paramètre ch correspond au caractère de remplacement que nous souhaitons. Celui-ci est de type gunichar qui correspond à l'encodage UCS-4. Bien que l'affichage de GTK+ se fasse avec l'encodage UTF-8, cela ne pose aucun problème, car cette fois-ci, la conversion est faite automatiquement.
Et pour terminer, la fonction permettant de connaître le caractère de remplacement est :
gunichar gtk_entry_get_invisble_char
(
GtkEntry *
entry);
IX-B-3. 2.3 Exemple▲
Cette fois, nous allons reprendre l'exemple précédent en activant le mode « mot de passe » et en limitant la saisie à huit caractères. Nous modifierons aussi le caractère de remplacement '*' par '$'.
IX-B-4. 2.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
on_activate_entry
(
GtkWidget *
pEntry, gpointer data);
void
on_copier_button
(
GtkWidget *
pButton, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pEntry;
GtkWidget *
pButton;
GtkWidget *
pLabel;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Le widget GtkEntry
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Creation du GtkEntry avec 8 caracteres maximum */
pEntry =
gtk_entry_new_with_max_length
(
8
);
/* Mode mot de passe */
gtk_entry_set_visibility
(
GTK_ENTRY
(
pEntry), FALSE);
/* Modification du caractère affiché */
gtk_entry_set_invisible_char
(
GTK_ENTRY
(
pEntry), '
$
'
);
/* Insertion du GtkEntry dans la GtkVBox */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pEntry, TRUE, FALSE, 0
);
pButton =
gtk_button_new_with_label
(
"
Copier
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
NULL
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pLabel, TRUE, FALSE, 0
);
/* Connexion du signal "activate" du GtkEntry */
g_signal_connect
(
G_OBJECT
(
pEntry), "
activate
"
, G_CALLBACK
(
on_activate_entry), (
GtkWidget*
) pLabel);
/* Connexion du signal "clicked" du GtkButton */
/* La donnée supplémentaire est la GtkVBox pVBox */
g_signal_connect
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
on_copier_button), (
GtkWidget*
) pVBox);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
/* Fonction callback execute lors du signal "activate" */
void
on_activate_entry
(
GtkWidget *
pEntry, gpointer data)
{
const
gchar *
sText;
/* Recuperation du texte contenu dans le GtkEntry */
sText =
gtk_entry_get_text
(
GTK_ENTRY
(
pEntry));
/* Modification du texte contenu dans le GtkLabel */
gtk_label_set_text
(
GTK_LABEL
((
GtkWidget*
)data), sText);
}
/* Fonction callback executee lors du signal "clicked" */
void
on_copier_button
(
GtkWidget *
pButton, gpointer data)
{
GtkWidget *
pTempEntry;
GtkWidget *
pTempLabel;
GList *
pList;
const
gchar *
sText;
/* Recuperation de la liste des éléments que contient la GtkVBox */
pList =
gtk_container_get_children
(
GTK_CONTAINER
((
GtkWidget*
)data));
/* Le premier élément est le GtkEntry */
pTempEntry =
GTK_WIDGET
(
pList->
data);
/* Passage a l élément suivant : le GtkButton */
pList =
g_list_next
(
pList);
/* Passage a l élément suivant : le GtkLabel */
pList =
g_list_next
(
pList);
/* Cet élément est le GtkLabel */
pTempLabel =
GTK_WIDGET
(
pList->
data);
/* Recuperation du texte contenu dans le GtkEntry */
sText =
gtk_entry_get_text
(
GTK_ENTRY
(
pTempEntry));
/* Modification du texte contenu dans le GtkLabel */
gtk_label_set_text
(
GTK_LABEL
(
pTempLabel), sText);
/* Liberation de la mémoire utilisée par la liste */
g_list_free
(
pList);
}
Résultat :
IX-C. En savoir plus▲
IX-C-1. Signaux▲
Prototypes fonctions callback :
-
activate
Sélectionnezvoid
user_function
(
GtkEntry*
entry, gpointer user_data); -
copy-clipboard
Sélectionnezvoid
user_function
(
GtkEntry*
entry, gpointer user_data); -
cut-clipboard
Sélectionnezvoid
user_function
(
GtkEntry*
entry, gpointer user_data); -
delete-from-cursor
Sélectionnezvoid
user_function
(
GtkEntry*
entry, GtkDeleteType arg1, gint arg2, gpointer user_data); -
insert-at-cursor
Sélectionnezvoid
user_function
(
GtkEntry*
entry, gchar*
arg1, gpointer user_data); -
move-cursor
Sélectionnezvoid
user_function
(
GtkEntry*
entry, GtkMovementStep arg1, gint arg2, gboolean arg3, gpointer user_data); -
paste-clipboard
Sélectionnezvoid
user_function
(
GtkEntry*
entry, gpointer user_data); -
populate-popup
Sélectionnezvoid
user_function
(
GtkEntry*
entry, GtkMenu*
arg1, gpointer user_data); - toggle-overwrite
void
user_function (
GtkEntry *
entry, gpointer user_data);
IX-C-2. Fonction documentée▲
void
gtk_entry_set_max_length
(
GtkEntry *
entry, gint max);
Définit le nombre maximum de caractères que l'utilisateur peut saisir.
Entrée(s) :
- entry : le GtkEntry.
- max : le nombre de caractères.
Sortie : rien.
gint gtk_entry_get_max_length
(
GtkEntry *
entry);
Récupère le nombre maximum de caractères que l'utilisateur peut saisir.
Entrée(s) :
- entry : le GtkEntry.
Sortie : le nombre maximum de caractères.
IX-C-3. Fonctions non documentées▲
gboolean gtk_entry_get_activates_default
(
GtkEntry *
entry);
void
gtk_entry_set_activates_default
(
GtkEntry *
entry, gboolean setting);
gboolean gtk_entry_get_has_frame
(
GtkEntry *
entry);
void
gtk_entry_set_has_frame
(
GtkEntry *
entry, gboolean setting);
gint gtk_entry_get_width_chars
(
GtkEntry *
entry);
void
gtk_entry_set_width_chars
(
GtkEntry *
entry, gint n_chars);
PangoLayout*
gtk_entry_get_layout
(
GtkEntry *
entry);
void
gtk_entry_get_layout_offsets
(
GtkEntry *
entry, gint *
x, gint *
y);
X. Les décorations▲
Maintenant, nous connaissons suffisamment de widgets pour créer des fenêtres complexes. Afin d'améliorer l'esthétique de ces fenêtres, nous allons voir comment ajouter des décorations (ou séparation) entre les différentes parties de la fenêtre. Il existe deux types de décoration :
- le cadre GtkFrame qui entoure toute une zone de la fenêtre et qui possède un texte permettant de définir la zone ;
- la ligne GtkSeparator qui divise en deux parties différentes, le widget GtkHSeparator pour les lignes horizontales et le widget GtkVSeparator pour les lignes verticales.
X-A. Le cadre▲
X-A-1. Création▲
Le widget GtkFrame étant très simple, il n'y a qu'une seule fonction de création :
GtkWidget*
gtk_frame_new
(
const
gchar *
label);
Le paramètre label est tout simplement le texte qui sera affiché en haut à gauche du cadre (position par défaut).
X-A-2. Modification du texte▲
Il peut arriver que dans votre application, le texte du cadre nécessite une modification. Bien entendu, le widget GtkFrame est fourni avec toutes les fonctions nécessaires.
void
gtk_frame_set_label
(
GtkFrame *
frame, const
gchar *
label);
Le paramètre frame est le widget GtkFrame dont nous voulons modifier le texte, et label est le nouveau texte à inscrire. Cette fois encore, il faut utiliser une macro de conversion pour le premier paramètre qui est cette fois GTK_FRAME().
Pour récupérer le texte du GtkFrame, la fonction est :
G_CONST_RETURN gchar*
gtk_frame_get_label
(
GtkFrame *
frame);
X-A-3. Remplacer le texte par un widget▲
Les cadres offrent aussi la possibilité de remplacer le texte par un widget quelconque (GtkImage, GtkStockItem…) grâce à cette fonction :
gtk_frame_set_label_widget
(
GtkFrame *
frame, GtkWidget *
label_widget);
Et comme toujours, la fonction permettant de connaître le widget affiché:
GtkWidget*
gtk_frame_get_label_widget
(
GtkFrame *
frame);
X-A-4. Position du texte▲
Par défaut, la position du texte est en haut à gauche du cadre, centré en hauteur par rapport à la ligne supérieure. Cela aussi peut être modifié avec cette fonction :
void
gtk_frame_set_label_align
(
GtkFrame *
frame, gfloat xalign, gfloat yalign);
Les valeurs xalign et yalign doivent être comprises entre 0.0 et 1.0.
Le paramètre xalign définit la position horizontale du texte. Une valeur de 0.0 positionne le texte à gauche du cadre, tandis qu'une valeur de 1.0 le positionne à droite. Évidemment, une valeur de 0.5 centrera le texte.
Quant à yalign, il permet de définir la position verticale du texte par rapport à la ligne supérieure du cadre. Une valeur de 0.0 mettra le nommeur en dessous de la ligne et une valeur de 1.0 le mettra au-dessus de la ligne.
On peut, bien sûr, connaître les valeurs de positionnement avec les fonctions suivantes :
void
gtk_frame_get_label_align
(
GtkFrame *
frame, gfloat *
xalign, gfloat *
yalign);
X-A-5. Style du cadre▲
Le style du cadre correspond plus à la configuration visuelle des lignes du cadre et plus précisément encore l'ombre des lignes. Cette modification de fait avec cette fonction :
void
gtk_frame_set_shadow_type
(
GtkFrame *
frame, GtkShadowType type);
Le paramètre type peut prendre cinq valeurs différentes dont voici la liste avec leurs illustrations :
Valeur de type |
Illustration de la ligne supérieure |
---|---|
GTK_SHADOW_NONE |
En fait, on ne voit pas la ligne. |
GTK_SHADOW_IN |
|
GTK_SHADOW_OUT |
|
GTK_SHADOW_ETCHED_IN (par défaut) |
|
GTK_SHADOW_ETCHED_OUT |
|
Et sans surprise, voici la fonction qui permet de connaître le type des lignes :
GtkShadowType gtk_frame_get_shadow_type
(
GtkFrame *
frame);
X-B. Les lignes▲
Alors cette fois, cela va être très rapide et très simple.
X-B-1. Création▲
GtkWidget*
gtk_hseparator_new
(
void
);
GtkWidget*
gtk_vseparator_new
(
void
);
La première fonction crée une ligne horizontale alors que la deuxième crée une ligne verticale.
Il n'y a rien de plus à propos de ce widget.
X-C. Exemple▲
X-C-1. Description▲
Afin de vous montrer l'avantage visuel de l'utilisation des GtkFrame et GtkSeparator, nous allons créer une fenêtre qui demande à l'utilisateur de saisir des informations le concernant (nom, prénom, adresse…).
Voilà à quoi ressemble la fenêtre sans l'utilisation des décorations :
Attention, ce programme ne fait rien du tout, c'est simplement pour montrer la différence entre avec et sans les décorations.
X-C-2. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pFrame;
GtkWidget *
pVBoxFrame;
GtkWidget *
pSeparator;
GtkWidget *
pEntry;
GtkWidget *
pLabel;
gchar *
sUtf8;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
/* On ajoute un espace de 5 sur les bords de la fenêtre */
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 5
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkEntry et GtkSeparator
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Creation du premier GtkFrame */
pFrame =
gtk_frame_new
(
"
Etat civil
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pFrame, TRUE, FALSE, 0
);
/* Creation et insertion d une boite pour le premier GtkFrame */
pVBoxFrame =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pVBoxFrame);
/* Creation et insertion des éléments contenus dans le premier GtkFrame */
pLabel =
gtk_label_new
(
"
Nom :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
sUtf8 =
g_locale_to_utf8
(
"
Prénom :
"
, -
1
, NULL
, NULL
, NULL
);
pLabel =
gtk_label_new
(
sUtf8);
g_free
(
sUtf8);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
/* Creation d un GtkHSeparator */
pSeparator =
gtk_hseparator_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pSeparator, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Date de naissance :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
/* Creation du deuxieme GtkFrame */
pFrame =
gtk_frame_new
(
"
Domicile
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pFrame, TRUE, FALSE, 0
);
/* Creation et insertion d une boite pour le deuxieme GtkFrame */
pVBoxFrame =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pVBoxFrame);
/* Creation et insertion des éléments contenus dans le deuxieme GtkFrame */
pLabel =
gtk_label_new
(
"
Adresse :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Adresse :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Code postal :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Ville :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
/* Creation du troisieme GtkFrame */
sUtf8 =
g_locale_to_utf8
(
"
Téléphones
"
, -
1
, NULL
, NULL
, NULL
);
pFrame =
gtk_frame_new
(
sUtf8);
g_free
(
sUtf8);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pFrame, TRUE, FALSE, 0
);
/* Creation et insertion d une boite pour le troisieme GtkFrame */
pVBoxFrame =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pVBoxFrame);
/* Creation et insertion des éléments contenus dans le troisieme GtkFrame */
pLabel =
gtk_label_new
(
"
Domicile
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Professionnel
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
pLabel =
gtk_label_new
(
"
Portable
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pLabel, TRUE, FALSE, 0
);
pEntry =
gtk_entry_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBoxFrame), pEntry, TRUE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XI. Les images▲
Nous allons cette fois, essayer de rendre nos fenêtres un peu moins austères. Pour cela, nous allons utiliser des images grâce au widget GtkImage. Nous allons voir comment afficher une image à partir d'un fichier ou d'un GtkStockItem.
XI-A. Utilisation du widget GtkImage▲
XI-A-1. Création▲
Pour ce widget, il y a toute une panoplie de fonction de création. Nous n'allons en étudier que quelques-unes, car certaines font appel à des notions par encore vues. Voici donc les fonctions étudiées :
GtkWidget*
gtk_image_new (
void
);
GtkWidget*
gtk_image_new_from_file
(
const
gchar *
filename);
GtkWidget*
gtk_image_new_from_stock
(
const
gchar *
stock_id, GtkIconSize size);
La première crée une image, mais complètement vide.
La deuxième crée l'image à partir du fichier filename. Gtk+ est capable d'utiliser les images qui sont au format PNG, JPEG, TIFF. Le chemin du fichier filename peut être relatif ou absolu. Si le chemin spécifié est incorrect ou que le format de l'image est invalide, l'image de retour sera celle-ci :
La troisième fonction, récupère l'image qui est associée à un objet GtkStockItem afin de l'afficher. Le paramètre size peut prendre sept valeurs différentes pour définir la taille de l'image à afficher :
Valeur |
Aperçu |
---|---|
GTK_ICON_SIZE_INVALID |
Ne peut être passé en paramètre. Ceci est uniquement une valeur de retour. |
GTK_ICON_SIZE_MENU |
|
GTK_ICON_SIZE_SMALL_TOOLBAR |
|
GTK_ICON_SIZE_LARGE_TOOLBAR |
|
GTK_ICON_SIZE_BUTTON |
|
GTK_ICON_SIZE_DND |
|
GTK_ICON_SIZE_DIALOG |
|
XI-A-2. Modification de l'image▲
Cette étape intervient lorsque vous avez créé une image vide ou lorsque vous voulez changer d'image. Les deux fonctions étudiées ici sont :
void
gtk_image_set_from_file
(
GtkImage *
image, const
gchar *
filename);
void
gtk_image_set_from_stock
(
GtkImage *
image, const
gchar *
stock_id, GtkIconSize size);
Les paramètres sont les mêmes que lors de la création d'un widget GtkImage, sauf qu'il faut préciser à quel widget il faut appliquer l'image.
XI-A-3. Exemple▲
Notre exemple comprendra deux composants. Tout d'abord une zone ou est affichée l'image, puis un bouton contenant l'image du GtkStockItem GTK_STOCK_QUIT, pour quitter l'application.
XI-A-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pImage;
GtkWidget *
pQuitImage;
GtkWidget *
pQuitBtn;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkImage
"
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Chargement d'une image à partir d'un fichier */
pImage =
gtk_image_new_from_file
(
"
./gtk.png
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pImage, FALSE, FALSE, 5
);
pQuitBtn =
gtk_button_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pQuitBtn, TRUE, FALSE, 5
);
g_signal_connect
(
G_OBJECT
(
pQuitBtn), "
clicked
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Chargement d'une image à partir d'un GtkStockItem */
pQuitImage =
gtk_image_new_from_stock
(
GTK_STOCK_QUIT, GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_container_add
(
GTK_CONTAINER
(
pQuitBtn), pQuitImage);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XI-B. En savoir plus▲
XI-B-1. Fonctions non documentées▲
void
gtk_image_get_icon_set
(
GtkImage *
image, GtkIconSet **
icon_set, GtkIconSize *
size);
void
gtk_image_get_image
(
GtkImage *
image, GdkImage **
gdk_image, GdkBitmap **
mask);
GdkPixbuf*
gtk_image_get_pixbuf
(
GtkImage *
image);
void
gtk_image_get_pixmap
(
GtkImage *
image, GdkPixmap **
pixmap, GdkBitmap **
mask);
void
gtk_image_get_stock
(
GtkImage *
image, gchar **
stock_id, GtkIconSize *
size);
GdkPixbufAnimation*
gtk_image_get_animation
(
GtkImage *
image);
GtkImageType gtk_image_get_storage_type
(
GtkImage *
image);
GtkWidget*
gtk_image_new_from_icon_set
(
GtkIconSet *
icon_set, GtkIconSize size);
GtkWidget*
gtk_image_new_from_image
(
GdkImage *
image, GdkBitmap *
mask);
GtkWidget*
gtk_image_new_from_pixbuf
(
GdkPixbuf *
pixbuf);
GtkWidget*
gtk_image_new_from_pixmap
(
GdkPixmap *
pixmap, GdkBitmap *
mask);
GtkWidget*
gtk_image_new_from_animation
(
GdkPixbufAnimation *
animation);
void
gtk_image_set_from_icon_set
(
GtkImage *
image, GtkIconSet *
icon_set, GtkIconSize size);
void
gtk_image_set_from_image
(
GtkImage *
image, GdkImage *
gdk_image, GdkBitmap *
mask);
void
gtk_image_set_from_pixbuf
(
GtkImage *
image, GdkPixbuf *
pixbuf);
void
gtk_image_set_from_pixmap
(
GtkImage *
image, GdkPixmap *
pixmap, GdkBitmap *
mask);
void
gtk_image_set_from_animation
(
GtkImage *
image, GdkPixbufAnimation *
animation);
void
gtk_image_set
(
GtkImage *
image, GdkImage *
val, GdkBitmap *
mask);
void
gtk_image_get
(
GtkImage *
image, GdkImage **
val, GdkBitmap **
mask);
XII. Les boites de dialogue▲
Nous allons dans ce chapitre étudier un style de fenêtre particulier : les boites de dialogue. Elles permettent de demander à l'utilisateur des informations ou alors d'afficher des messages. Ces boites de dialogue ressemblant fortement à des fenêtres classiques, il est normal que le widget GtkDialog dérive directement de GtkWindow.
XII-A. Utilisation d'une boite de saisie▲
La saisie d'information via le widget GtkEntry ne s'effectue presque jamais dans la fenêtre principale, mais dans une boite de dialogue. Nous allons donc voir comment créer une telle boite.
XII-A-1. Constitution d'une boite de dialogue▲
Comme nous pouvons le voir sur l'image ci-dessus, une boite de dialogue est constituée de trois éléments :
- une GtkVBox globale (en rouge) qui contiendra tous les widgets affichés ;
- une GtkHSeparator (en vert) qui sert de séparation entre la zone de saisie et la zone des boutons ;
- une GtkHBox (en bleu) qui contiendra les boutons de réponse.
On peut donc ainsi distinguer deux zones différentes :
- la zone de travail au-dessus de la GtkHSeparator ;
- la zone de réponse au-dessous de la GtkHSeparator.
XII-A-2. Création▲
La fonction de création est un peu plus complexe que d'habitude :
GtkWidget*
gtk_dialog_new_with_buttons
(
const
gchar *
title, GtkWindow *
parent, GtkDialogFlags flags, const
gchar *
first_button_text, ...);
Le premier paramètre title n'est autre que le titre de la boite de dialogue.
Le deuxième paramètre parent sert à désigner la fenêtre parente. Cette valeur peut être égale à NULL.
Le troisième paramètre flags permet de définir certains paramètres de la boite de dialogue. Ce paramètre peut prendre trois valeurs différentes :
- GTK_DIALOG_MODAL : créer une boite de dialogue modale, c'est-à-dire que tant que l'utilisateur n'a pas cliqué sur un des boutons de réponse, les autres fenêtres seront figées ;
- GTK_DIALOG_DESTROY_WITH_PARENT : la boite de dialogue est détruite si la fenêtre parente est détruite ;
- GTK_DIALOG_NO_SEPARATOR : la ligne de séparation entre la zone de travail et la zone de réponse n'est pas affichée.
Enfin, le dernier paramètre est plutôt une liste de paramètres permettant de définir les boutons de la boite de dialogue ainsi que les réponses qui leur sont associées. Pour chaque bouton que nous voulons ajouter, il faut définir le texte du bouton et le type de réponse qui sera envoyé lorsque nous cliquerons sur le bouton.
Le texte du bouton peut, comme pour tous les boutons, être un texte normal, un texte avec raccourci (Rappel : c'est de la forme « _Quitter ») ou même un GtkStockItem.
La valeur de la réponse, peut être un élément de type GtkResponseType ou bien une valeur entière positive que nous pouvons définir nous-mêmes. Le plus simple étant bien sûr d'utiliser les valeurs classiques définies par le type GtkResponseType dont voici la liste :
- GTK_RESPONSE_NONE ;
- GTK_RESPONSE_REJECT ;
- GTK_RESPONSE_ACCEPT ;
- GTK_RESPONSE_DELETE_EVENT ;
- GTK_RESPONSE_OK ;
- GTK_RESPONSE_CANCEL ;
- GTK_RESPONSE_CLOSE ;
- GTK_RESPONSE_YES ;
- GTK_RESPONSE_NO ;
- GTK_RESPONSE_APPLY ;
- GTK_RESPONSE_HELP.
Une fois que tous les boutons ont été définis, il faut le dire à notre fonction de création. Pour cela, il suffit de terminer la liste des paramètres par NULL.
La majeure partie des éléments de la boite de dialogue sont maintenant créés. Il reste cependant à ajouter les éléments de la zone de travail pour que la boite soit complète. Une fois que tous les éléments à ajouter dans la zone de travail sont créés, il suffit de les ajouter dans la boite de dialogue avec la fonction gtk_box_pack_start.
La question est maintenant de savoir comment passer la GtkVBox en paramètre à la fonction gtk_box_pack_start. Nous allons tout simplement utiliser l'opérateur -> pour l'élément GtkDialog de cette manière :
GTK_DIALOG
(
nom_de_la_boite)->
vbox;
La boite de dialogue est maintenant complète.
XII-A-3. Affichage▲
L'affichage de la boite de dialogue comporte deux étapes. Tout d'abord, il faut demander d'afficher tout le contenu de la GtkVBox qui est incluse dans la boite de dialogue avec la fonction gtk_widget_show_all.
Ensuite il faut afficher la boite de dialogue en elle-même et attendre la réponse de l'utilisateur avec cette fonction :
gint gtk_dialog_run
(
GtkDialog *
dialog);
Le paramètre de cette fonction étant de type GtkDialog il faut utiliser la macro de conversion GTK_DIALOG().
Cette fonction affiche l'intégralité de la boite de dialogue, mais rentre aussi dans une boucle récursive qui ne s'arrêtera que lorsque l'utilisateur cliquera sur un des boutons. La valeur de retour correspond à la valeur associée au bouton cliqué. Si, par hasard, l'utilisateur quitte la boite de dialogue en cliquant sur la croix de celle-ci, gtk_dialog_run renvoie GTK_RESPONSE_NONE.
Une fois la valeur de retour connue, il ne reste plus qu'à agir en conséquence.
XII-A-4. Exemple▲
L'exemple de ce chapitre est constitué d'une fenêtre principale dans laquelle nous allons ajouter un GtkButton et un GtkLabel. Lorsque l'utilisateur clique sur le GtkButton, une boite de dialogue apparaîtra et demandera à l'utilisateur de saisir son nom.
Cette boite de dialogue sera constituée d'une GtkEntry, d'un GtkButton « OK » et d'un GtkButton « Annuler ». Si l'utilisateur clique sur « OK » le contenu de la GtkEntry sera copié dans le GtkLabel de la fenêtre principale tandis que s'il clique sur « Annuler » on affichera « Vous n'avez rien saisi. » dans le GtkLabel.
XII-A-5. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
static
GtkWidget *
pLabel;
static
GtkWidget *
pWindow;
void
lancer_boite
(
void
);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pVBox;
GtkWidget *
pButton;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkDialog
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
pButton =
gtk_button_new_with_label
(
"
Cliquez ici pour saisir votre nom
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton, FALSE, TRUE, 0
);
pLabel =
gtk_label_new
(
NULL
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pLabel, FALSE, FALSE, 0
);
/* Connexion du signal "clicked" pour ouvrir la boite de dialogue */
g_signal_connect
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
lancer_boite), NULL
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
lancer_boite
(
void
)
{
GtkWidget*
pBoite;
GtkWidget*
pEntry;
const
gchar*
sNom;
/* Création de la boite de dialogue */
/* 1 bouton Valider */
/* 1 bouton Annuler */
pBoite =
gtk_dialog_new_with_buttons
(
"
Saisie du nom
"
,
GTK_WINDOW
(
pWindow),
GTK_DIALOG_MODAL,
GTK_STOCK_OK,GTK_RESPONSE_OK,
GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,
NULL
);
/* Création de la zone de saisie */
pEntry =
gtk_entry_new
(
);
gtk_entry_set_text
(
GTK_ENTRY
(
pEntry), "
Saisissez votre nom
"
);
/* Insertion de la zone de saisie dans la boite de dialogue */
/* Rappel : paramètre 1 de gtk_box_pack_start de type GtkBox */
gtk_box_pack_start
(
GTK_BOX
(
GTK_DIALOG
(
pBoite)->
vbox), pEntry, TRUE, FALSE, 0
);
/* Affichage des éléments de la boite de dialogue */
gtk_widget_show_all
(
GTK_DIALOG
(
pBoite)->
vbox);
/* On lance la boite de dialogue et on récupéré la réponse */
switch
(
gtk_dialog_run
(
GTK_DIALOG
(
pBoite)))
{
/* L utilisateur valide */
case
GTK_RESPONSE_OK:
sNom =
gtk_entry_get_text
(
GTK_ENTRY
(
pEntry));
gtk_label_set_text
(
GTK_LABEL
(
pLabel), sNom);
break
;
/* L utilisateur annule */
case
GTK_RESPONSE_CANCEL:
case
GTK_RESPONSE_NONE:
default
:
gtk_label_set_text
(
GTK_LABEL
(
pLabel), "
Vous n'avez rien saisi !
"
);
break
;
}
/* Destruction de la boite de dialogue */
gtk_widget_destroy
(
pBoite);
}
Résultat :
XII-B. Les boites de messages▲
Comme nous venons de le voir, le widget GtkDialog permet d'accélérer la programmation de simple fenêtre de saisie. Pour ce qui est de l'affichage de message, GTK+ offre un nouveau widget qui dérive directement de GtkDialog : le widget GtkMessageDialog. Ce widget permet de créer une boite de dialogue complète avec une seule fonction.
XII-B-1. Création▲
L'unique fonction de ce widget est la fonction permettant de créer la boite de dialogue :
GtkWidget*
gtk_message_dialog_new
(
GtkWindow *
parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, const
gchar *
message_format, ...);
Les paramètres parents et flags sont identiques à ceux du widget GtkDialog, nous ne reviendrons donc pas dessus et allons nous concentrer sur les nouveaux paramètres.
Le tout premier type permet de définir le texte qui sera affiché dans la barre de titre de la boite de dialogue ainsi que l'icône correspondant. Ce paramètre est de type GtkMessageType et peut prendre une des quatre valeurs suivantes :
Valeur |
Titre de la boite de dialogue |
Icône |
---|---|---|
GTK_MESSAGE_INFO |
Information |
|
GTK_MESSAGE_WARNING |
Avertissement |
|
GTK_MESSAGE_QUESTION |
Question |
|
GTK_MESSAGE_ERROR |
Erreur |
|
Le deuxième nouveau paramètre buttons permet de définir les boutons qui seront présents en bas de la boite de dialogue. Les valeurs autorisées sont les suivantes :
Macro |
Les boutons |
Valeur de retour |
---|---|---|
GTK_BUTTONS_NONE |
Aucun bouton |
Néant |
GTK_BUTTONS_OK |
Un bouton Ok |
GTK_RESPONSE_OK |
GTK_BUTTONS_CLOSE |
Un bouton Fermer |
GTK_RESPONSE_CLOSE |
GTK_BUTTONS_CANCEL |
Un bouton Annuler |
GTK_RESPONSE_CANCEL |
GTK_BUTTONS_YES_NO |
Un bouton Oui |
GTK_RESPONSE_YES |
GTK_BUTTONS_OK_CANCEL |
Un bouton Ok |
GTK_RESPONSE_OK |
Et le dernier paramètre message_format est tout simplement le texte qui sera affiché à l'intérieur de la boite de dialogue. Ce texte peut être formaté comme il est possible de le faire avec la fonction printf.
XII-B-2. Exemple▲
Nous allons créer une fenêtre comportant deux boutons. Le premier permettra d'afficher les informations habituelles d'une boite de dialogue « À propos… ». Le deuxième offrira la possibilité de quitter le programme, en passant par une demande de confirmation à l'utilisateur.
XII-B-3. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
on_about_btn
(
GtkWidget *
pBtn, gpointer data);
void
on_quitter_btn
(
GtkWidget *
pBtn, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pQuitterBtn;
GtkWidget *
pAboutBtn;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkMessageDialog
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
TRUE,0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow),pVBox);
pAboutBtn =
gtk_button_new_with_label
(
"
À propos...
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pAboutBtn, TRUE, FALSE,0
);
g_signal_connect
(
G_OBJECT
(
pAboutBtn), "
clicked
"
, G_CALLBACK
(
on_about_btn), (
GtkWidget*
) pWindow);
pQuitterBtn =
gtk_button_new_from_stock (
GTK_STOCK_QUIT);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pQuitterBtn, TRUE, FALSE, 0
);
g_signal_connect
(
G_OBJECT
(
pQuitterBtn), "
clicked
"
, G_CALLBACK
(
on_quitter_btn), (
GtkWidget*
) pWindow);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
on_about_btn
(
GtkWidget *
pBtn, gpointer data)
{
GtkWidget *
pAbout;
gchar *
sSite =
"
http://gtk.developpez.com
"
;
/* Création de la boite de message */
/* Type : Information -> GTK_MESSAGE_INFO */
/* Bouton : 1 OK -> GTK_BUTTONS_OK */
pAbout =
gtk_message_dialog_new (
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Cours GTK+ 2.0
\n
%s
"
,
sSite);
/* Affichage de la boite de message */
gtk_dialog_run
(
GTK_DIALOG
(
pAbout));
/* Destruction de la boite de message */
gtk_widget_destroy
(
pAbout);
}
void
on_quitter_btn
(
GtkWidget*
widget, gpointer data)
{
GtkWidget *
pQuestion;
/* Création de la boite de message */
/* Type : Question -> GTK_MESSAGE_QUESTION */
/* Boutons : 1 OUI, 1 NON -> GTK_BUTTONS_YES_NO */
pQuestion =
gtk_message_dialog_new (
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"
Voulez-vous vraiment
\n
quitter ce programme?
"
);
/* Affichage et attente d une réponse */
switch
(
gtk_dialog_run
(
GTK_DIALOG
(
pQuestion)))
{
case
GTK_RESPONSE_YES:
/* OUI -> on quitte l application */
gtk_main_quit
(
);
break
;
case
GTK_RESPONSE_NO:
/* NON -> on détruit la boite de message */
gtk_widget_destroy
(
pQuestion);
break
;
}
}
Résultat :
XII-C. En savoir plus▲
XII-C-1. Fonctions documentées▲
GtkWidget*
gtk_dialog_new
(
);
Permet de créer une boite de dialogue vierge.
Entrée(s) : rien.
Sortie : pointeur sur la boite de dialogue.
void
gtk_dialog_add_buttons
(
GtkDialog *
dialog, const
gchar *
first_button_text, ...);
Ajoute des boutons à la boite de dialogue.
Entrée(s) :
- dialog : la boite de dialogue.
- first_button_text… : texte et réponse des boutons.
Sortie : rien.
GtkWidget*
gtk_dialog_add_button
(
GtkDialog *
dialog, const
gchar *
button_text, gint response_id);
Ajoute un bouton à la boite de dialogue.
Entrée(s) :
- dialog : la boite de dialogue.
- button_text : texte du bouton.
- response_id : valeur de retour du bouton .
Sortie : pointeur sur le nouveau bouton.
gboolean gtk_dialog_get_has_separator
(
GtkDialog *
dialog);
Pour savoir si la boite de dialogue possède une barre de séparation.
Entrée(s) :
- dialog : la boite de dialogue.
Sortie : TRUE si la barre de séparation est présente, FALSE sinon.
void
gtk_dialog_set_has_separator
(
GtkDialog *
dialog, gboolean setting);
Définit si la boite de dialogue possède une barre de séparation
Entrée(s) :
- dialog : la boite de dialogue en question
- setting : TRUE pour l'ajouter, FALSE sinon.
Sortie : rien.
XII-C-2. Fonctions non documentées▲
void
gtk_dialog_response
(
GtkDialog *
dialog, gint response_id);
void
gtk_dialog_set_default_response
(
GtkDialog *
dialog, gint response_id);
void
gtk_dialog_set_response_sensitive
(
GtkDialog *
dialog, gint response_id, gboolean setting);
void
gtk_dialog_add_action_widget
(
GtkDialog *
dialog, GtkWidget *
child, gint response_id);
XIII. Les boutons (partie 2)▲
Nous allons étudier cette fois-ci trois nouveaux types de boutons qui dérivent du widget GtkButton (chapitre VLes boutons (partie 1)). L'étude de ces widgets sera rapide, car ils ne comportent que très peu de fonctions.
XIII-A. Le widget GtkToggleButton▲
Il s'agit ici d'un bouton poussoir qui ne peut prendre que deux états : enfoncé ou relâché. Ce widget dérive de GtkButton.
XIII-A-1. Création du bouton▲
Vous allez voir ici, il n'y a rien de bien compliqué vu que c'est toujours le même principe :
GtkWidget*
gtk_toggle_button_new
(
void
);
GtkWidget*
gtk_toggle_button_new_with_label
(
const
gchar*
label);
GtkWidget*
gtk_toggle_button_new_with_mnemonics
(
const
gchar*
label);
La première fonction crée un nouveau bouton vide, alors que la seconde ajoute du texte à l'intérieur et la troisième ajoute en plus un raccourci clavier.
XIII-A-2. États du bouton▲
Il peut être intéressant de connaître l'état du bouton pour agir en conséquence. Une fois encore, rien de plus simple on utilise la fonction :
gboolean gtk_toggle_button_get_active
(
GtkToggleButton *
toggle_button);
Cette dernière nous renvoie TRUE si le bouton est enfoncé et FALSE sinon. Afin de pouvoir utiliser le paramètre toggle_button qui est le bouton dont on veut connaître l'état, il faut utiliser la macro GTK_TOGGLE_BUTTON().
Pour modifier l'état du bouton, c'est aussi simple :
void
gtk_toggle_button_set_active
(
GtkToggleButton *
toggle_button, gboolean is_active);
Il suffit de mettre le paramètre is_active à TRUE si l'on veut enfoncer le bouton ou à FALSE pour le relâcher.
Il existe cependant un troisième état qui n'est pas accessible en cliquant sur le bouton, mais par une fonction spécifique. Ce troisième état, vous le connaissez sûrement. Le meilleur exemple est celui des éditeurs de texte :
Vous avez une phrase dans laquelle il y a du texte normal et du texte en gras. Si vous sélectionnez le texte en gras, le bouton permettant justement de le mettre en gras s'enfonce (en général B). Par contre si vous sélectionnez le texte normal, ce même bouton repasse à son état relâché. Venons-en au troisième état, qui apparaît lorsque vous sélectionnez la phrase entière. Le bouton ne change pas d'état, mais seulement d'aspect, il donne l'impression d'être inactif.
Ce changement d'aspect doit se faire manuellement, et s'effectue avec cette fonction :
void
gtk_toggle_button_set_inconsistent
(
GtkToggleButton *
toggle_button, gboolean setting);
Il suffit de mettre le paramètre setting à TRUE pour donner au bouton l'aspect inactif.
Et pour connaître l'aspect du bouton, il y a tout naturellement la fonction :
gboolean gtk_toggle_button_get_inconsistent
(
GtkToggleButton *
toggle_button);
Évidemment, toutes les fonctions du widget GtkButton sont utilisables avec ce type de bouton.
XIII-A-3. Exemple▲
Nous allons construire une application contenant un GtkToggleButton qui changera d'état (bien sûr) lorsque nous cliquerons dessus, mais aussi lorsque nous cliquerons sur un deuxième bouton (le changement d'état entraînera la modification du label). De plus, il y aura un troisième bouton pour changer l'aspect du bouton (idem, on change aussi le label).
La création des widgets étant classique, nous n'allons donc pas revenir dessus.
Il va donc nous falloir trois fonctions callback. La première pour changer le texte lorsque l'on clique sur le GtkToggleButton, la deuxième pour changer son état lorsque l'on clique sur le deuxième bouton, et la troisième pour changer l'aspect.
Pour la première fonction callback, il faut intercepter le signal « toggled » qui est émis lorsque le bouton change d'état :
g_signal_connect
(
G_OBJECT
(
pToggleBtn), "
toggled
"
, G_CALLBACK
(
OnToggle), NULL
);
Dans cette fonction nous allons récupérer l'état du bouton ainsi que son aspect afin de changer le label en fonction des valeurs de retour.
Pour la deuxième, on interceptera le signal « clicked » :
g_signal_connect
(
G_OBJECT
(
pEtatBtn), "
clicked
"
, G_CALLBACK
(
OnEtatBtn), pToggleBtn);
Lorsque l'on changera l'état du bouton toggle, le signal « toggled » sera émis pour celui-ci et le texte se changera automatiquement.
Pour la troisième, le signal à intercepter et le même (« clicked ») :
g_signal_connect
(
G_OBJECT
(
pAspectBtn), "
clicked
"
, G_CALLBACK
(
OnAspectBtn), pToggleBtn);
Cette fois, lorsque l'on change l'aspect du bouton, le signal « toggled » n'est pas émis et le texte ne changera donc pas. Il faut donc émettre soit même ce signal avec la fonction :
void
gtk_toggle_button_toggled (
GtkToggleButton *
toggle_button);
Cette fonction ne change en aucun cas l'état du bouton, elle ne fait qu'émettre le signal.
Mais le plus simple est de regarder le code source suivant.
XIII-A-4. 1.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnToggle
(
GtkWidget *
pToggle, gpointer data);
void
OnEtatBtn
(
GtkWidget *
pWidget, gpointer pToggle);
void
OnAspectBtn
(
GtkWidget *
pWidget, gpointer pToggle);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pToggleBtn;
GtkWidget *
pEtatBtn;
GtkWidget *
pAspectBtn;
GtkWidget *
pVBox;
gchar *
sLabel;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkToggleButton
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Création du label du bouton */
sLabel =
g_locale_to_utf8
(
"
Etat : Relâché - Aspect : Normal
"
, -
1
, NULL
, NULL
, NULL
);
/* Création du bouton GtkToggleButton */
pToggleBtn =
gtk_toggle_button_new_with_label
(
sLabel);
/* Le label sLabel n'est plus utile */
g_free
(
sLabel);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pToggleBtn, FALSE, FALSE, 0
);
pEtatBtn =
gtk_button_new_with_label
(
"
CHANGER ETAT
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pEtatBtn, FALSE, FALSE, 0
);
pAspectBtn =
gtk_button_new_with_label
(
"
CHANGER ASPECT
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pAspectBtn, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
/* Connexion des signaux */
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
g_signal_connect
(
G_OBJECT
(
pToggleBtn), "
toggled
"
, G_CALLBACK
(
OnToggle), NULL
);
g_signal_connect
(
G_OBJECT
(
pEtatBtn), "
clicked
"
, G_CALLBACK
(
OnEtatBtn), pToggleBtn);
g_signal_connect
(
G_OBJECT
(
pAspectBtn), "
clicked
"
, G_CALLBACK
(
OnAspectBtn), pToggleBtn);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnEtatBtn
(
GtkWidget *
pWidget, gpointer pToggle)
{
gboolean bEtat;
/* Recuperation de l'état du bouton */
bEtat =
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
pToggle));
/* Modification de l'état du bouton */
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
pToggle), (
bEtat ^
TRUE));
}
void
OnAspectBtn
(
GtkWidget *
pEtatBtn, gpointer pToggle)
{
gboolean bInconsistent;
/* Récupération de l aspect du bouton */
bInconsistent =
gtk_toggle_button_get_inconsistent
(
GTK_TOGGLE_BUTTON
(
pToggle));
/* Modification de l'aspect du bouton */
gtk_toggle_button_set_inconsistent
(
GTK_TOGGLE_BUTTON
(
pToggle), (
bInconsistent ^
TRUE));
/* On émet le signal "toggle" pour changer le texte du bouton */
gtk_toggle_button_toggled
(
GTK_TOGGLE_BUTTON
(
pToggle));
}
void
OnToggle
(
GtkWidget *
pToggle, gpointer data)
{
gboolean bEtat;
gboolean bInconsistent;
gchar *
sLabel;
gchar *
sLabelUtf8;
/* Récupération de l'état du bouton */
bEtat =
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
pToggle));
/* Recuperation de l aspect du bouton */
bInconsistent =
gtk_toggle_button_get_inconsistent
(
GTK_TOGGLE_BUTTON
(
pToggle));
/* Construction du label du bouton */
sLabel =
g_strdup_printf
(
"
Etat : %s - Aspect : %s
"
,
bEtat ? "
Enfoncé
"
: "
Relâché
"
,
bInconsistent ? "
Modifié
"
: "
Normal
"
);
/* Encodage du label en UTF8 */
sLabelUtf8 =
g_locale_to_utf8
(
sLabel, -
1
, NULL
, NULL
, NULL
);
/* Modification du label du bouton */
gtk_button_set_label
(
GTK_BUTTON
(
pToggle), sLabelUtf8);
/* Les chaînes sLabel et sLabelUtf8 n'ont plus d'utilité */
g_free
(
sLabel);
g_free
(
sLabelUtf8);
}
Résultat :
XIII-B. Le widget GtkCheckButton▲
Sous ce nom se cachent tout simplement les cases à cocher que tout le monde connaît. Il s'agit là aussi d'un type de bouton binaire, d'ailleurs ce widget dérive de GtkToggleButton :
XIII-B-1. Création d'un GtkCheckButton▲
Une fois encore, la syntaxe et l'utilisation des fonctions de création restent classiques :
GtkWidget*
gtk_check_button_new
(
void
);
GtkWidget*
gtk_check_button_new_with_label
(
const
gchar *
label);
GtkWidget*
gtk_check_button_new_with_mnemonic
(
const
gchar *
label);
XIII-B-2. Utilisation d'un GtkCheckButton▲
Il n'existe pas d'autres fonctions pour ce widget, il faut donc utiliser les fonctions des widgets GtkToggleButton et GtkButton pour récupérer les propriétés du widget (état, aspect, label…).
Nous n'allons pas ici créer de programme exemple pour ce widget, car il suffit de remplacer gtk_toggle_button_new_with_label par gtk_check_button_new_with_label dans l'exemple précédent pour obtenir ceci :
XIII-C. Le widget GtkRadioButton▲
Nous passons maintenant au widget GtkRadioButton qui se différencie par la possibilité d'en grouper plusieurs. De ce fait, lors que par exemple nous avons un groupe de trois boutons, il n'y en a qu'un seul qui peut être actif. On pourrait très bien faire cela avec le widget GtkCheckButton, mais cela serait beaucoup plus long à programmer. Dans la hiérarchie des widgets, GtkRadioButton dérive de GtkCheckButton.
XIII-C-1. Création d'un groupe de GtkRadioButton.▲
Afin de grouper les boutons radio, GTK+ utilise les listes simplement chaînées de GLib. Pour créer le premier bouton radio du groupe, il faut obligatoirement passer par une de ces fonctions :
GtkWidget*
gtk_radio_button_new
(
GSList *
group);
GtkWidget*
gtk_radio_button_new_with_label
(
GSList *
group, const
gchar *
label);
GtkWidget*
gtk_radio_button_new_with_mnemonic
(
GSList *
group, const
gchar *
label);
Au moment de la création, le bouton radio est automatiquement ajouté à la liste group. Cependant, ce paramètre n'est pas obligatoire. Nous pouvons très bien mettre NULL comme valeur et cela marchera de la même manière, sauf que nous n'aurons pas de pointeur sur la liste. La valeur de retour de cette fonction sera aussi copiée dans la variable data de la liste chaînée.
Ensuite pour rajouter les autres boutons au groupe, il y a plusieurs possibilités. La première est d'utiliser une des trois fonctions précédentes, mais ce n'est pas tout, car autant pour le premier bouton du groupe, il n'est pas nécessaire d'avoir une liste, autant pour les autres boutons cela devient obligatoire. Pour cela, GTK+ nous fournit une fonction qui permet d'obtenir la liste dans laquelle les boutons du groupe sont ajoutés :
GSList*
gtk_radio_button_get_group
(
GtkRadioButton *
radio_button);
Avec cette fonction, nous pouvons donc connaître la liste à laquelle appartient le bouton radio_button, ce qui va nous permettre d'ajouter de nouveau bouton au groupe. Mais là où cela se complique, c'est qu'il faut récupérer la liste avant chaque ajout de bouton avec le dernier bouton ajouté comme paramètre. Voici ce que cela donnerait pour un groupe de trois boutons :
pRadio1 =
gtk_radio_button_new_with_label
(
NULL
, "
Radio 1
"
);
pGroup =
gtk_radio_button_get_group
(
GTK_RADIO_BUTTON
(
pRadio1));
pRadio2 =
gtk_radio_button_new_with_label
(
pGroup, "
Radio 2
"
);
pGroup =
gtk_radio_button_get_group
(
GTK_RADIO_BUTTON
(
pRadio2));
pRadio3 =
gtk_radio_button_new_with_label
(
pGroup, "
Radio 3
"
);
Ce système peut donc s'avérer lourd lors de la création du groupe, surtout s'il contient un grand nombre de boutons. Heureusement, les concepteurs de GTK+ ont pensé à nous simplifier la vie en ajoutant ces trois fonctions :
GtkWidget*
gtk_radio_button_new_from_widget
(
GtkRadioButton *
group);
GtkWidget*
gtk_radio_button_new_with_label_from_widget
(
GtkRadioButton *
group, const
gchar *
label);
GtkWidget*
gtk_radio_button_new_with_mnemonic_from_widget
(
GtkRadioButton *
group, const
gchar *
label);
Cette fois group ne correspond pas à la liste, mais à un des boutons du groupe. À chaque appel d'une de ces fonctions, GTK+ va s'occuper de récupérer correctement la liste à laquelle appartient le bouton group et ajouter le nouveau bouton. Cela aura pour conséquence, dans le cas d'un groupe de trois boutons, de réduire le nombre de lignes de code de 5 à 3 (et oui, une ligne de code c'est une ligne de code).
Nous savons maintenant tout ce qu'il faut pour créer un groupe de GtkRadioButton.
XIII-C-2. Exemple▲
Le programme exemple se présente sous la forme d'un mini sondage à trois choix :
- Pour ;
- Contre ;
- Sans opinion.
La possibilité de choisir parmi une de ces valeurs est rendue possible par l'utilisation des GtkRadioButton. Un autre bouton (tout ce qu'il y a de plus normal) permet de valider le choix fait par l'utilisateur ainsi que d'afficher le résultat dans une boite de dialogue.
XIII-C-3. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnValider
(
GtkWidget *
pBtn, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pRadio1;
GtkWidget *
pRadio2;
GtkWidget *
pRadio3;
GtkWidget *
pValider;
GtkWidget *
pLabel;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkRadioButton
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
pVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow),pVBox);
pLabel =
gtk_label_new
(
"
Votre choix :
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pLabel, FALSE, FALSE, 0
);
/* Création du premier bouton radio */
pRadio1 =
gtk_radio_button_new_with_label
(
NULL
, "
Pour
"
);
gtk_box_pack_start
(
GTK_BOX (
pVBox), pRadio1, FALSE, FALSE, 0
);
/* Ajout du deuxieme */
pRadio2 =
gtk_radio_button_new_with_label_from_widget
(
GTK_RADIO_BUTTON (
pRadio1), "
Contre
"
);
gtk_box_pack_start
(
GTK_BOX (
pVBox), pRadio2, FALSE, FALSE, 0
);
/* Ajout du troisième */
pRadio3 =
gtk_radio_button_new_with_label_from_widget
(
GTK_RADIO_BUTTON (
pRadio1), "
Sans opinion
"
);
gtk_box_pack_start
(
GTK_BOX (
pVBox), pRadio3, FALSE, FALSE, 0
);
pValider =
gtk_button_new_from_stock
(
GTK_STOCK_OK);
gtk_box_pack_start
(
GTK_BOX (
pVBox), pValider, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
/* Connexion des signaux */
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
g_signal_connect
(
G_OBJECT
(
pValider), "
clicked
"
, G_CALLBACK
(
OnValider), pRadio1);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnValider
(
GtkWidget *
pBtn, gpointer data)
{
GtkWidget *
pInfo;
GtkWidget *
pWindow;
GSList *
pList;
const
gchar *
sLabel;
/* Récupération de la liste des boutons */
pList =
gtk_radio_button_get_group
(
GTK_RADIO_BUTTON
(
data));
/* Parcours de la liste */
while
(
pList)
{
/* Le bouton est-il sélectionné */
if
(
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
pList->
data)))
{
/* OUI -> on copie le label du bouton */
sLabel =
gtk_button_get_label
(
GTK_BUTTON
(
pList->
data));
/* On met la liste a NULL pour sortir de la boucle */
pList =
NULL
;
}
else
{
/* NON -> on passe au bouton suivant */
pList =
g_slist_next
(
pList);
}
}
/* On récupère la fenêtre principale */
/*
/* À partir d'un widget, gtk_widget_get_toplevel
/* remonte jusqu'à la fenêtre mère qui nous est
/* utile pour l'affichage de la boite de dialogue
*/
pWindow = gtk_widget_get_toplevel(GTK_WIDGET(data));
pInfo = gtk_message_dialog_new(GTK_WINDOW(pWindow),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Vous avez choisi : %s", sLabel);
gtk_dialog_run(GTK_DIALOG(pInfo));
gtk_widget_destroy(pInfo);
}
Résultat :
XIII-D. En savoir plus▲
XIII-D-1. Fonctions documentées▲
GtkToggleButton
Sélectionnez
|
Définit si le bouton est visible ou pas.
Sortie : rien |
Sélectionnez
|
Pour savoir si le bouton est visible ou pas.
Sortie : TRUE si le bouton est visible, FALSE sinon. |
GtkRadioButton
Sélectionnez
|
Pour changer un bouton radio de groupe.
Sortie : rien |
XIV. Les menus▲
Nous allons cette fois voir quelles sont les solutions que GTK+ met à notre disposition pour ajouter un menu à une fenêtre. Nous parlons de « solutions » au pluriel, car il existe en fait deux méthodes possibles à la création d'un menu, l'une étant plus rapide que l'autre.
Ce chapitre est composé de trois parties distinctes :
- Une première partie traitant de la création d'un menu classique par la méthode la plus longue ;
- Une deuxième partie dans laquelle nous verrons des éléments spéciaux d'un menu ;
- La troisième partie abordera la création d'un menu par la méthode rapide.
XIV-A. Le menu - Méthode longue▲
Pour construire un tel menu, nous allons utiliser pas moins de trois widgets différents qui serviront tous à différentes étapes de la création. Ces widgets sont GtkMenuBar, GtkMenu, GtkMenuItem dont voici leurs positions dans la hiérarchie GTK+ :
XIV-A-1. Les éléments d'un menu▲
Dans un premier temps, le plus simple est de voir comment seront disposés ces trois widgets dans notre futur menu.
Nous avons tous d'abord le widget GtkMenuBar (en rouge) qui est l'élément principal de notre menu. Il contient des éléments de type GtkMenuItem (en bleu) qui peuvent ouvrir des éléments GtkMenu (en vert) contenant aussi des GtkMenuItem.
Du point de vue du fonctionnement, les éléments GtkMenuItem peuvent soit ouvrir un sous-menu (élément GtkMenu) soit exécuter l'action qui lui est associée par l'intermédiaire d'une fonction callback. Il ne reste maintenant plus qu'à créer notre menu.
XIV-A-2. Création d'un menu▲
La création d'un menu doit passer par au moins six étapes différentes :
- Étape 1 : création de l'élément GtkMenuBar qui sera la barre de menu;
- Étape 2 : création d'un élément GtkMenu qui sera un menu ;
- Étape 3 : création des éléments GtkMenuItem à insérer dans le menu ;
- Étape 4 : création de l'élément GtkMenuItem qui ira dans l'élément GtkMenuBar ;
- Étape 5 : association de cet élément avec le menu créé précédemment ;
- Étape 6 : ajout de l'élément GtkMenuItem dans la barre GtkMenuBar.
Si par la suite, vous souhaitez ajouter d'autres menus, il suffit de recommencer à partir de l'étape 2. Étudions maintenant les fonctions qui vont nous permettre de coder le menu.
Étape 1 : création de l'élément GtkMenuBar
- Cette étape, rapide et simple, se résume en l'utilisation d'une seule fonction :
GtkWidget*
gtk_menu_bar_new
(
void
);
Étape 2 : création d'un élément GtkMenu qui sera un menu
- Cette fois aussi, une seule fonction est utilisée :
GtkWidget*
gtk_menu_new
(
void
);
Étape 3 : création des éléments GtkMenuItem à insérer dans le menu
- Dans un premier temps, il faut créer le GtkMenuItem grâce à l'une de ces trois fonctions :
GtkWidget*
gtk_menu_item_new
(
void
);
GtkWidget*
gtk_menu_item_new_with_label
(
const
gchar*
label);
GtkWidget*
gtk_menu_item_new_with_mnemonic
(
const
gchar*
label);
Nous reconnaissons la syntaxe de ces constructeurs qui est semblable à celles des boutons. La première fonction créer un élément vide, la deuxième un élément avec un texte (label), et la troisième un élément avec un texte associé à un raccourci.
Maintenant que l'élément est créé, il faut l'insérer dans le menu. Pour cela, il existe plusieurs fonctions possibles, mais nous n'allons en voir que deux :
void
gtk_menu_shell_append
(
GtkMenuShell *
menu_shell, GtkWidget *
child);
void
gtk_menu_shell_prepend
(
GtkMenuShell *
menu_shell, GtkWidget *
child);
Ces fonctions ne font pas partie du widget GtkMenu, mais de GtkMenuShell qui est le widget dont GtkMenu dérive. La première fonction ajoute les éléments de haut en bas alors que la seconde les ajoute de bas en haut. Le paramètre menu_shell est le menu dans lequel nous voulons ajouter l'élément et le paramètre child est l'élément à ajouter. Pour le premier paramètre, il faudra utiliser la macro de conversion GTK_MENU_SHELL().
Cette étape peut s'avérer longue à coder, car il faudra la répéter pour chaque élément que nous voulons ajouter au menu.
Étape 4 : création de l'élément GtkMenuItem qui ira dans l'élément GtkMenuBar
- Il suffit d'utiliser une des trois fonctions de création du widget GtkMenuItem.
Étape 5 : association de cet élément avec le menu créé précédemment
- Il faut maintenant dire que lorsque l'utilisateur cliquera sur l'élément créer pendant l'étape 4, il faudra ouvrir le menu qui a été créé précédemment. La fonction adéquate est celle-ci :
void
gtk_menu_item_set_submenu
(
GtkMenuItem *
menu_item, GtkWidget *
submenu);
Cette fonction va donc associer le GtkMenuItem menu_item au GtkMenu submenu. Comme d'habitude, il faudra convertir le premier paramètre, cette fois-ci à l'aide de la macro GTK_MENU_ITEM().
Étape 6 : ajout de l'élément GtkMenuItem dans la barre GtkMenuBar
- GtkMenuBar dérivant aussi de GtkMenuShell, nous allons utiliser la même fonction que lors de l'étape 3 (gtk_menu_shell_append) pour ajouter le sous-menu au menu principal.
XIV-A-3. Exemple▲
Notre exemple comportera deux menus. Le premier « Fichier », proposera des fonctions inactives (« Nouveau », « Ouvrir », « Enregistrer », « Fermer ») et une fonction active (« Quitter »), alors que le second « ? » proposera la fonction « À propos de… ».
XIV-A-4. 1.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnQuitter
(
GtkWidget*
widget, gpointer data);
void
OnAbout
(
GtkWidget*
widget, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pMenuBar;
GtkWidget *
pMenu;
GtkWidget *
pMenuItem;
gtk_init
(&
argc, &
argv);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkMenu
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Création de la GtkVBox */
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/**
** Création du menu ***
*/
/* ÉTAPE 1 */
pMenuBar =
gtk_menu_bar_new
(
);
/**
Premier sous-menu *
*/
/* ÉTAPE 2 */
pMenu =
gtk_menu_new
(
);
/* ÉTAPE 3 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
Nouveau
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_menu_item_new_with_label
(
"
Ouvrir
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_menu_item_new_with_label
(
"
Enregistrer
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_menu_item_new_with_label
(
"
Fermer
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_menu_item_new_with_label
(
"
Quitter
"
);
g_signal_connect
(
G_OBJECT
(
pMenuItem), "
activate
"
, G_CALLBACK
(
OnQuitter),(
GtkWidget*
) pWindow);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* ÉTAPE 4 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
Fichier
"
);
/* ÉTAPE 5 */
gtk_menu_item_set_submenu
(
GTK_MENU_ITEM
(
pMenuItem), pMenu);
/* ÉTAPE 6 */
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenuBar), pMenuItem);
/**
Second sous-menu *
*/
/* ÉTAPE 2 */
pMenu =
gtk_menu_new
(
);
/* ÉTAPE 3 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
À propos de...
"
);
g_signal_connect
(
G_OBJECT
(
pMenuItem), "
activate
"
, G_CALLBACK
(
OnAbout),(
GtkWidget*
) pWindow);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* ÉTAPE 4 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
?
"
);
/* ÉTAPE 5 */
gtk_menu_item_set_submenu
(
GTK_MENU_ITEM
(
pMenuItem), pMenu);
/* ÉTAPE 6 */
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenuBar), pMenuItem);
/* Ajout du menu a la fenêtre */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pMenuBar, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnQuitter
(
GtkWidget*
widget, gpointer data)
{
GtkWidget *
pQuestion;
pQuestion =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"
Voulez vous vraiment
\n
"
"
quitter le programme?
"
);
switch
(
gtk_dialog_run
(
GTK_DIALOG
(
pQuestion)))
{
case
GTK_RESPONSE_YES:
gtk_main_quit
(
);
break
;
case
GTK_RESPONSE_NONE:
case
GTK_RESPONSE_NO:
gtk_widget_destroy
(
pQuestion);
break
;
}
}
void
OnAbout
(
GtkWidget*
widget, gpointer data)
{
GtkWidget *
pAbout;
pAbout =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Cours GTK+ 2.0
\n
"
"
http://gtk.developpez.com
"
);
gtk_dialog_run
(
GTK_DIALOG
(
pAbout));
gtk_widget_destroy
(
pAbout);
}
Résultat :
XIV-B. Éléments « avancés » de menu▲
En plus des GtkMenuItem, GTK+ offre cinq éléments de menu additionnels prêts à l'emploi : GtkImageMenuItem, GtkRadioMenuItem, GtkCheckMenuItem, GtkSeparatorMenuItem et GtkTearoffMenuItem. Bien entendu toutes les fonctions s'appliquant sur des GtkMenuItem s'appliquent aussi à ces items (héritage oblige).
- GtkImageMenuItem est un widget qui permet de créer une entrée de menu textuelle avec une icône juste devant, par exemple :
- GtkRadioMenuItem est un widget qui marche en groupe, un seul GtkRadioMenuItem d'un groupe peut être activé comme dans l'exemple ci-dessous.
« Groupe 1 : choix 1 » et « Groupe 1 : choix 2 » font partie d'un premier groupe,
« Groupe 2 : choix 1 », « Groupe 2 : choix 2 » et « Groupe 2 : choix 3 » font partie d'un deuxième.
Seule une entrée du premier groupe peut être activée (ici c'est « Groupe 1 : choix 1 ») et pareil pour le deuxième groupe (où l'entrée activée est « Groupe 2 : choix 1 ») :
- GtkCheckMenuItem est un widget à trois états que l'on peut cocher :
- GtkSeparatorMenuItem est un widget qui sert simplement à séparer des parties de menu grâce à une ligne horizontale. Leur but est uniquement décoratif :
- GtkTearoffMenuItem est un widget qui permet de détacher le menu de sa barre et d'en faire une fenêtre à part entière :
Le menu encore attaché (le GtkTearoffMenuItem c'est les pointillés en haut du menu)
Le menu une fois détaché
XIV-B-1. Les GtkImageMenuItem▲
Pour créer un GtkImageMenuItem, on a à disposition quatre fonctions :
GtkWidget*
gtk_image_menu_item_new
(
void
);
GtkWidget*
gtk_image_menu_item_new_from_stock
(
const
gchar *
stock_id, GtkAccelGroup *
accel_group);
GtkWidget*
gtk_image_menu_item_new_with_label
(
const
gchar *
label);
GtkWidget*
gtk_image_menu_item_new_with_mnemonic
(
const
gchar *
label);
On retrouve encore les mêmes types de fonctions de création, aussi je passe sur l'explication des paramètres. La seule nouveauté est peut-être le GtkAccelGroup *accel_group de gtk_image_menu_item_new_from_stock, qui sert à ajouter l'entrée à un GtkAccelGroup précédemment créé en utilisant le raccourci par défaut de l'icône stock.
Maintenant, il s'agit de définir une icône pour notre entrée, pour cela, on a :
void
gtk_image_menu_item_set_image
(
GtkImageMenuItem *
image_menu_item, GtkWidget *
image);
Cette fonction permet de définir l'icône (généralement on utilisera un GtkImage) qui sera affichée par l'entrée passée en paramètre. Cette fonction peut aussi servir à remplacer l'icône que gtk_image_menu_item_new_from_stock définit pour l'entrée lors de sa création.
La dernière fonction spécifique des GtkImageMenuItem est :
GtkWidget*
gtk_image_menu_item_get_image
(
GtkImageMenuItem *
image_menu_item);
Elle sert, comme vous l'aurez deviné, à récupérer ce qui sert d'icône à l'entrée.
XIV-B-2. Les GtkCheckMenuItem▲
Les GtkCheckMenuItem émettent un signal lorsqu'on les (dé)coche, il s'agit du signal « toggled » et dont la fonction de rappel est de la forme
void
user_function
(
GtkCheckMenuItem *
checkmenuitem, gpointer user_data);
Les fonctions de création d'un GtkCheckMenuItem sont :
GtkWidget*
gtk_check_menu_item_new
(
void
);
GtkWidget*
gtk_check_menu_item_new_with_label
(
const
gchar *
label);
GtkWidget*
gtk_check_menu_item_new_with_mnemonic
(
const
gchar *
label);
Rien de nouveau à l'horizon, alors nous continuons.
Nous avons plusieurs fonctions qui permettent de changer l'état de notre GtkCheckMenuItem par programme :
void
gtk_check_menu_item_set_active
(
GtkCheckMenuItem *
check_menu_item, gboolean is_active);
void
gtk_check_menu_item_set_inconsistent
(
GtkCheckMenuItem *
check_menu_item, gboolean setting);
void
gtk_check_menu_item_toggled
(
GtkCheckMenuItem *
check_menu_item);
La première fonction pemet de passer le GtkCheckMenuItem dans l'état « coché » si le paramètre is_active est TRUE ou dans l'état « non coché » si is_active est FALSE. Cette fonction ne permet pas de mettre notre GtkCheckMenuItem dans le troisième état « demi coché », pour cela, il faut utiliser la deuxième fonction, et grâce au paramètre setting, on active ou non cet état. La troisième fonction, elle, permet d'alterner entre état « coché » et « non coché », car elle émet en fait le signal « toggled », ce qui a pour effet d'inverser l'état du GtkCheckMenuItem.
Nous disposons également des fonctions associées pour récupérer l'état d'un GtkCheckMenuItem :
gboolean gtk_check_menu_item_get_active
(
GtkCheckMenuItem *
check_menu_item);
gboolean gtk_check_menu_item_get_inconsistent
(
GtkCheckMenuItem *
check_menu_item);
La première permet de connaître l'état d'un GtkCheckMenuItem, elle renvoie TRUE s'il est « coché » ou FALSE sinon.
La deuxième permet juste de savoir si le GtkCheckMenuItem est dans le troisième état « demi coché ».
XIV-B-3. Les GtkRadioMenuItem▲
Les GtkRadioMenuItem héritent des GtkCheckMenuItem, donc tout ce qui a été dit juste avant s'applique aussi ici.
Pour créer un GtkRadioMenuItem, nous pouvons nous servir de :
GtkWidget*
gtk_radio_menu_item_new
(
GSList *
group);
GtkWidget*
gtk_radio_menu_item_new_with_label
(
GSList *
group, const
gchar *
label);
GtkWidget*
gtk_radio_menu_item_new_with_mnemonic
(
GSList *
group, const
gchar *
label);
Ce widget fonctionne de la même manière que le widget GtkRadioButton, et donc le paramètre group de ces fonctions, sert à dire au GtkRadioMenuItem à quel groupe il va appartenir.
Le premier GtkRadioMenuItem d'un groupe prendra toujours NULL comme paramètre group, de cette façon il va en créer un nouveau. Ensuite, il suffira de récupérer ce paramètre group grâce à la fonction suivante et de le passer à un autre GtkRadioMenuItem pour que celui-ci fasse partie du même groupe que le premier.
GSList*
gtk_radio_menu_item_get_group
(
GtkRadioMenuItem *
radio_menu_item);
Tout comme pour le widget GtkRadioButton, quand on crée un groupe de GtkRadioMenuItem, il faut toujours récupérer le groupe du GtkRadioMenuItem précédemment créé (sauf pour le premier bien entendu)
On peut aussi définir ou remplacer le groupe d'un GtkRadioMenuItem aprés coup grâce à :
void
gtk_radio_menu_item_set_group
(
GtkRadioMenuItem *
radio_menu_item, GSList *
group);
XIV-B-4. Les GtkSeparatorMenuItem▲
Ah, en voilà un widget qu'il est bien !
Une seule fonction pour sa création, et c'est tout :
GtkWidget*
gtk_separator_menu_item_new
(
void
);
Ça c'est des fonctions qu'on aime ;-)
XIV-B-5. Les GtkTearoffMenuItem▲
Pour le créer faites :
GtkWidget*
gtk_tearoff_menu_item_new
(
void
);
Et c'est tout ! Ensuite, un premier clic sur l'élément GtkTearoffMenuItem créera une copie du menu dans une fenêtre, et un second clic sur l'élément (que cela soit dans le menu ou dans la fenêtre) supprimera la fenêtre créée.
Pour savoir si le menu est attaché ou détaché, il faut utiliser la fonction :
gboolean gtk_menu_get_tearoff_state
(
GtkMenu *
menu);
Cette dernière renverra TRUE si le menu est détaché et FALSE sinon.
Lorsque nous fermons la fenêtre du menu détaché à la main (c'est-à-dire lorsque nous cliquons sur la croix), le menu est automatiquement réattaché, mais gtk_menu_get_tearoff_state renverra tout de même TRUE.
XIV-B-6. Programme exemple▲
Nous avons repris l'exemple précédent en modifiant le menu pour y mettre nos nouveaux items et en y ajoutant trois labels pour indiquer l'état des différents items. Il y a aussi trois callbacks supplémentaires pour la mise à jour de nos labels.
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnQuitter
(
GtkWidget*
widget, gpointer data);
void
OnAbout
(
GtkWidget*
widget, gpointer data);
void
OnRadio
(
GtkWidget*
widget, gpointer data);
void
OnTearoff
(
GtkWidget*
widget, gpointer data);
void
OnCheck
(
GtkWidget*
widget, gpointer data);
static
GtkWidget *
pRadioLabel;
static
GtkWidget *
pCheckLabel;
static
GtkWidget *
pTearoffLabel;
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pVBox2;
GtkWidget *
pMenuBar;
GtkWidget *
pMenu;
GtkWidget *
pMenuItem;
GSList *
pList;
gchar *
sTempLabel;
gtk_init
(&
argc, &
argv);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkMenu
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Création de la GtkVBox */
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/**
** Création du menu ***
*/
/* ÉTAPE 1 */
pMenuBar =
gtk_menu_bar_new
(
);
/**
Premier sous-menu *
*/
/* ÉTAPE 2 */
pMenu =
gtk_menu_new
(
);
/* ÉTAPE 3 */
/* GtkTearoffMenuItem */
pMenuItem =
gtk_tearoff_menu_item_new
(
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
g_signal_connect
(
G_OBJECT
(
pMenuItem),"
activate
"
,G_CALLBACK
(
OnTearoff),(
gpointer)pMenu);
/* GtkImageMenuItem */
pMenuItem =
gtk_image_menu_item_new_from_stock
(
GTK_STOCK_NEW,NULL
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_image_menu_item_new_from_stock
(
GTK_STOCK_OPEN,NULL
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_image_menu_item_new_from_stock
(
GTK_STOCK_SAVE,NULL
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_image_menu_item_new_from_stock
(
GTK_STOCK_CLOSE,NULL
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* GtkSeparatorItem */
pMenuItem =
gtk_separator_menu_item_new
(
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* GtkRadioMenuItem */
pMenuItem =
gtk_radio_menu_item_new_with_label
(
NULL
, "
Radio 1
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pList =
gtk_radio_menu_item_get_group
(
GTK_RADIO_MENU_ITEM
(
pMenuItem));
/* Il est inutile ici d'utiliser le signal "toggled" */
g_signal_connect
(
G_OBJECT
(
pMenuItem), "
activate
"
, G_CALLBACK
(
OnRadio), NULL
);
pMenuItem =
gtk_radio_menu_item_new_with_label
(
pList, "
Radio 2
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pList =
gtk_radio_menu_item_get_group
(
GTK_RADIO_MENU_ITEM
(
pMenuItem));
g_signal_connect
(
G_OBJECT
(
pMenuItem) ,"
activate
"
, G_CALLBACK
(
OnRadio), NULL
);
pMenuItem =
gtk_radio_menu_item_new_with_label
(
pList, "
Radio 3
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pList =
gtk_radio_menu_item_get_group
(
GTK_RADIO_MENU_ITEM
(
pMenuItem));
g_signal_connect
(
G_OBJECT
(
pMenuItem) ,"
activate
"
, G_CALLBACK
(
OnRadio), NULL
);
/* GtkSeparatorItem */
pMenuItem =
gtk_separator_menu_item_new
(
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* GtkCheckMenuItem */
pMenuItem =
gtk_check_menu_item_new_with_label
(
"
Check
"
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
g_signal_connect
(
G_OBJECT
(
pMenuItem),"
toggled
"
,G_CALLBACK
(
OnCheck),(
gpointer)pMenu);
/* GtkSeparatorItem */
pMenuItem =
gtk_separator_menu_item_new
(
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
pMenuItem =
gtk_image_menu_item_new_from_stock
(
GTK_STOCK_QUIT,NULL
);
g_signal_connect
(
G_OBJECT
(
pMenuItem), "
activate
"
, G_CALLBACK
(
OnQuitter), (
GtkWidget*
) pWindow);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* ÉTAPE 4 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
Fichier
"
);
/* ÉTAPE 5 */
gtk_menu_item_set_submenu
(
GTK_MENU_ITEM
(
pMenuItem), pMenu);
/* ÉTAPE 6 */
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenuBar), pMenuItem);
/**
Deuxieme sous-menu *
*/
/* ÉTAPE 2 */
pMenu =
gtk_menu_new
(
);
/* ÉTAPE 3 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
À propos de...
"
);
g_signal_connect
(
G_OBJECT
(
pMenuItem), "
activate
"
, G_CALLBACK
(
OnAbout), (
GtkWidget*
) pWindow);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenu), pMenuItem);
/* ÉTAPE 4 */
pMenuItem =
gtk_menu_item_new_with_label
(
"
?
"
);
/* ÉTAPE 5 */
gtk_menu_item_set_submenu
(
GTK_MENU_ITEM
(
pMenuItem), pMenu);
/* ÉTAPE 6 */
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
pMenuBar), pMenuItem);
/* Creation de la deuxieme GtkVBox (pour les labels) */
pVBox2 =
gtk_vbox_new
(
FALSE, 0
);
pRadioLabel =
gtk_label_new
(
"
Radio 1 est actif
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox2), pRadioLabel, TRUE, TRUE, 0
);
sTempLabel =
g_locale_to_utf8
(
"
Check est décoché
"
, -
1
, NULL
, NULL
, NULL
);
pCheckLabel =
gtk_label_new
(
sTempLabel);
g_free
(
sTempLabel);
gtk_box_pack_start
(
GTK_BOX
(
pVBox2), pCheckLabel, TRUE, TRUE, 0
);
sTempLabel =
g_locale_to_utf8
(
"
Menu attaché
"
, -
1
, NULL
, NULL
, NULL
);
pTearoffLabel =
gtk_label_new
(
sTempLabel);
g_free
(
sTempLabel);
gtk_box_pack_start
(
GTK_BOX
(
pVBox2), pTearoffLabel, TRUE, TRUE, 0
);
/* Ajout du menu a la fenêtre */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pMenuBar, FALSE, FALSE, 0
);
/* Ajout des labels a la fenêtre */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pVBox2, TRUE, TRUE, 0
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnRadio
(
GtkWidget*
widget, gpointer data)
{
const
gchar *
sRadioName;
gchar *
sLabel;
/* Récupérer le label du bouton radio active */
sRadioName =
gtk_label_get_label
(
GTK_LABEL
(
GTK_BIN
(
widget)->
child));
sLabel =
g_strdup_printf
(
"
%s est actif
"
,sRadioName);
gtk_label_set_label
(
GTK_LABEL
(
pRadioLabel), sLabel);
g_free
(
sLabel);
}
void
OnCheck
(
GtkWidget*
widget, gpointer data)
{
gboolean bCoche;
gchar *
sLabel;
gchar *
sLabelUtf8;
/* Savoir si le GtkCheckMenuItem est coche ou non */
bCoche =
gtk_check_menu_item_get_active
(
GTK_CHECK_MENU_ITEM
(
widget));
if
(
bCoche)
sLabel =
g_strdup
(
"
Check est coché
"
);
else
sLabel =
g_strdup
(
"
Check est décoché
"
);
sLabelUtf8 =
g_locale_to_utf8
(
sLabel, -
1
, NULL
, NULL
, NULL
);
gtk_label_set_label
(
GTK_LABEL
(
pCheckLabel), sLabelUtf8);
g_free
(
sLabel);
g_free
(
sLabelUtf8);
}
void
OnTearoff
(
GtkWidget*
widget, gpointer data)
{
gboolean bDetache;
gchar *
sLabel;
gchar *
sLabelUtf8;
/* Savoir si le menu est détaché ou non */
bDetache =
gtk_menu_get_tearoff_state
(
GTK_MENU
(
data));
if
(
bDetache)
sLabel =
g_strdup
(
"
Menu détaché
"
);
else
sLabel =
g_strdup
(
"
Menu attaché
"
);
sLabelUtf8 =
g_locale_to_utf8
(
sLabel, -
1
, NULL
, NULL
, NULL
);
gtk_label_set_label
(
GTK_LABEL
(
pTearoffLabel), sLabelUtf8);
g_free
(
sLabel);
g_free
(
sLabelUtf8);
}
void
OnQuitter
(
GtkWidget*
widget, gpointer data)
{
GtkWidget *
pQuestion;
pQuestion =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"
Voulez vous vraiment
\n
"
"
quitter le programme?
"
);
switch
(
gtk_dialog_run
(
GTK_DIALOG
(
pQuestion)))
{
case
GTK_RESPONSE_YES:
gtk_main_quit
(
);
break
;
case
GTK_RESPONSE_NONE:
case
GTK_RESPONSE_NO:
gtk_widget_destroy
(
pQuestion);
break
;
}
}
void
OnAbout
(
GtkWidget*
widget, gpointer data)
{
GtkWidget *
pAbout;
pAbout =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Cours GTK+ 2.0
\n
"
"
http://gtk.developpez.com
"
);
gtk_dialog_run
(
GTK_DIALOG
(
pAbout));
gtk_widget_destroy
(
pAbout);
}
Résultat :
XIV-C. Le menu - Méthode rapide▲
Cette méthode est obsolète depuis GTK+ 2.4, il est fortement conseillé d'utiliser GtkUIManager en remplacement.
Grâce aux deux premières parties du chapitre, nous avons appris à créer un menu. Vous avez pu remarquer que cette méthode peut s'avérer très fastidieuse si le menu comporte beaucoup d'éléments. Nous allons maintenant voir comment simplifier tout cela pour le biais de l'objet GtkItemFactory.
XIV-C-1. Fonctionnement de GtkItemFactory▲
L'objet GtkItemFactory n'est en fait qu'une grosse machine nous fournissant les fonctions nécessaires à la création d'un menu. Pour cela, GtkItemFactory utilise la structure GtkItemFactoryEntry qui elle nous permet de définir les différents éléments qui composent le menu ainsi que les actions qui leurs sont associés. Voici la définition de la structure GtkItemFactoryEntry :
struct
GtkItemFactoryEntry {
gchar *
path;
gchar *
accelerator;
GtkItemFactoryCallback callback;
guint callback_action;
gchar *
item_type;
gconstpointer extra_data;
}
;
XIV-C-2. Création des éléments du menu▲
Pour cela, la seule à faire est de déclarer et de remplir un tableau de GtkItemFactoryEntry. Nous allons donc maintenant étudier comment remplir ce tableau d'après la définition de la structure GtkItemFactoryEntry.
Le paramètre path correspond au chemin de l'élément dans l'arborescence du menu. Il faut pour cela, voir l'arborescence d'un menu comme celle des fichiers, c'est-à-dire organisée en répertoire (les branches du menu) et en fichier (les éléments du menu). Ce paramètre permet aussi de définir le texte de l'élément. Par exemple, nous avons un menu « Fichier » qui possède un élément « Nouveau », alors le path de la branche « Fichier » sera « /Fichier » et celui de l'élément « Nouveau » sera « /Fichier/Nouveau ». Pour souligner une lettre (pour indiquer un raccourci clavier), il faut précéder cette lettre de « _ » comme pour les mnémoniques. Cependant, cela ne crée pas un raccourci, il s'agit juste d'une indication.
Le second paramètre accelerator définit la combinaison de touche qui activera l'élément du menu, et cela, même si le menu n'est pas ouvert. La combinaison de touche allouée à l'élément est affichée après le label de l'élément du menu. La syntaxe de ce paramètre est « <touche_speciale>Lettre », touche_spéciale pouvant être Ctrl, Alt ou Shift. Voici donc le récapitulatif des solutions possibles :
Valeur |
Touche |
---|---|
<ALT> |
Alt |
<CTRL> <CONTROL> <CTL> |
Control |
<SHFT> <SHIFT> |
Shift |
Il est bien sûr possible d'utiliser une combinaison de ces touches (exemple : « <CTRL><SHIFT>O »).
Le paramètre callback est la fonction callback qui sera appelée lorsque l'élément sera activé à l'aide de la souris ou d'un raccourci clavier.
Le quatrième paramètre, callback_action, a plusieurs incidences sur la fonction callback. Tout d'abord, si callback_action est égal à 0, la fonction callback devra avoir ce prototype :
void
fonction_callback
(
void
);
Dans tous les autres cas, le prototype sera :
void
fonction_callback
(
gpointer callback_data, gint callback_action, GtkWidget *
widget);
Dans ce cas, callback_data est la donnée supplémentaire envoyée à la fonction callback, callback_action et identique à la valeur donnée à l'élément et widget est l'élément lui-même.
Le cinquième paramètre, item_type, définit de quoi est constitué l'élément du menu. Ce paramètre doit être une des valeurs suivantes :
Valeur |
Type d'élément |
---|---|
« <Branch> » |
Élément ouvrant un autre menu. |
NULL, « « , »<Item> » |
Élément classique avec du texte. |
« <StockItem> » |
Elément de type GtkStockItem. |
« <ImageItem> » |
Élément de type GtkImageMenuItem. |
« <CheckItem> » |
Élément de type GtkCheckMenuItem. |
« <ToggleItem> » |
Elément de type GtkToggleBtn. |
« <RadioItem> » |
Élément de type GtkRadioMenuItem. |
« path » |
Élément de type GtkRadioMenuItem. |
« <Title> » |
Affiche seulement le texte (grisé) de l'élément. Ce dernier ne peut être sélectionné. |
« <Separator> » |
Une ligne de séparation. |
« <Tearoff> » |
Élément pour détacher une partie du menu |
« <LastBranch> » |
Élément ouvrant un autre menu. Met l'élément à droite de la barre de menu. |
La seule subtilité ici, est pour les éléments de type GtkRadioMenuItem. Le premier bouton radio du groupe (ex. : path = « /Choix/Pour ») aura item_type égal à « <RadioItem> » alors que les autres auront item_type égal à « /Choix/Pour ».
Enfin pour terminer, le dernier paramètre extra_data devra être défini dans deux cas :
- l'élément est de type « <StockItem> », alors extra_data sera l'identifiant du GtkStockItem à afficher dans le menu ;
- l'élément est de type « <ImageItem> », alors extra_data sera un pointeur sur le GdkPixmap (pas encore étudié à ce stade du cours) à afficher.
Nous savons donc maintenant comment déclarer le menu et il ne reste plus qu'à le créer.
XIV-C-3. Création du menu▲
La première chose à faire est de créer un objet pour récupérer les raccourcis clavier du menu. Pour cela nous allons utiliser l'objet GtkAccelGroup dont nous n'allons pas parler ici. La création de cet objet se fait à l'aide de cette fonction :
GtkAccelGroup*
gtk_accel_group_new
(
void
);
Ensuite il faut créer l'objet GtkItemFactory avec cette fonction :
GtkItemFactory*
gtk_item_factory_new
(
GType container_type, const
gchar *
path, GtkAccelGroup *
accel_group);
Le premier paramètre container_type, définit le type de menu que nous voulons créer. Il existe trois valeurs possibles :
- GTK_TYPE_MENU_BAR, qui créera une barre de menu tout ce qu'il y a de plus normal ;
- GTK_TYPE_MENU, qui créera un menu qui servira pour faire un menu popup ;
- GTK_TYPE_OPTION_MENU, qui créera une sorte de bouton qui ouvrira le menu une fois cliqué.
Le paramètre path est le nom que nous donnons au menu. Il représente la racine du menu et doit avoir la syntaxe suivante « <nom_du_menu> ».
Le dernier paramètre permet de récupérer les raccourcis clavier dans le GtkAccelGroup. Ce paramètre peut être égal à NULL.
Une fois le menu créé, il faut y insérer tous ses éléments avec la fonction :
void
gtk_item_factory_create_items
(
GtkItemFactory *
ifactory, guint n_entries, GtkItemFactoryEntry *
entries, gpointer callback_data);
Voici le détail des différents paramètres :
- ifactory est le GtkItemFactory que nous venons de créer ;
- n_entries est le nombre d'éléments que nous allons ajouter ;
- entries est le tableau de GtkItemFactoryEntry qui a été crée au début ;
- callback_data est la donnée supplémentaire qui sera envoyé aux différentes fonctions callback. Cette donnée est unique et sera envoyée pour tous les éléments de entries qui ont le paramètre callback_action différents de zéro.
Il faut ensuite récupérer de tout cela un GtkWidget pour pouvoir l'ajouter à notre fenêtre. Pour cela, il faut utiliser cette fonction :
GtkWidget*
gtk_item_factory_get_widget
(
GtkItemFactory *
ifactory, const
gchar *
path);
Les paramètres sont respectivement le GtkItemFactory créé précédemment (ifactory) avec le nom qui lui est associé (path).
Et pour terminer tout cela, il faut associer les raccourcis à la fenêtre contenant le menu. Cela est possible par le biais d'une fonction du widget GtkWindow :
void
gtk_window_add_accel_group
(
GtkWindow *
window, GtkAccelGroup *
accel);
Et voilà, le menu est terminé.
XIV-C-4. 3.4 Exemple▲
Nous allons reprendre l'exemple de la première partie, mais cette en utilisant des éléments de menu de type « <StockItem> ». En plus de cela, nous rajouterons en bas de la fenêtre un menu de type GTK_TYPE_OPTION_MENU.
XIV-C-5. 3.5 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnQuitter
(
gpointer data, guint callback_action,GtkWidget *
widget);
void
OnAbout
(
gpointer data, guint callback_action,GtkWidget *
widget);
/* Définition des éléments du menu */
static
GtkItemFactoryEntry MenuItem[] =
{
{
"
/_Fichier
"
, NULL
, NULL
, 0
, "
<Branch>
"
}
,
{
"
/Fichier/_Nouveau
"
, NULL
, NULL
, 0
, "
<StockItem>
"
, GTK_STOCK_NEW }
,
{
"
/Fichier/_Ouvrir
"
, NULL
, NULL
, 0
, "
<StockItem>
"
, GTK_STOCK_OPEN }
,
{
"
/Fichier/Enregi_strer
"
, "
<ctrl>S
"
, NULL
, 0
, "
<StockItem>
"
, GTK_STOCK_SAVE }
,
{
"
/Fichier/_Fermer
"
, "
<ctrl>F
"
, NULL
, 0
, "
<StockItem>
"
, GTK_STOCK_CLOSE }
,
{
"
/Fichier/Sep1
"
, NULL
, NULL
, 0
, "
<Separator>
"
}
,
{
"
/Fichier/_Quitter
"
, NULL
, OnQuitter, 1
, "
<StockItem>
"
, GTK_STOCK_QUIT}
,
{
"
/_?
"
, NULL
, NULL
, 0
, "
<Branch>
"
}
,
{
"
/?/_A propos de...
"
, "
<CTRL>A
"
, OnAbout, 1
, "
<StockItem>
"
, GTK_STOCK_HELP}
}
;
/* Nombre d' éléments du menu */
static
gint iNbMenuItem =
sizeof
(
MenuItem) /
sizeof
(
MenuItem[0
]);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pMenuBar;
GtkItemFactory *
pItemFactory;
GtkAccelGroup *
pAccel;
gtk_init
(&
argc, &
argv);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
Les menus
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Création de la table d'accélération */
pAccel =
gtk_accel_group_new
(
);
/* Création du menu */
pItemFactory =
gtk_item_factory_new
(
GTK_TYPE_MENU_BAR, "
<main>
"
, pAccel);
/* Récupération des éléments du menu */
gtk_item_factory_create_items
(
pItemFactory, iNbMenuItem, MenuItem, (
GtkWidget*
)pWindow);
/* Récupération du widget pour l'affichage du menu */
pMenuBar =
gtk_item_factory_get_widget
(
pItemFactory, "
<main>
"
);
/* Ajout du menu en haut de la fenêtre */
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pMenuBar, FALSE, FALSE, 0
);
/* Association des raccourcis avec la fenêtre */
gtk_window_add_accel_group
(
GTK_WINDOW
(
pWindow), pAccel);
/* Création d un second menu de type GTK_TYPE_OPTION_MENU */
pItemFactory =
gtk_item_factory_new
(
GTK_TYPE_OPTION_MENU, "
<main>
"
, NULL
);
/* Récupération des éléments du menu */
gtk_item_factory_create_items
(
pItemFactory, iNbMenuItem, MenuItem, (
GtkWidget*
)pWindow);
/* Récupération du widget pour l'affichage du menu */
pMenuBar =
gtk_item_factory_get_widget
(
pItemFactory, "
<main>
"
);
/* Ajout du menu en bas de la fenêtre */
gtk_box_pack_end
(
GTK_BOX
(
pVBox), pMenuBar, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnQuitter
(
gpointer data, guint callback_action,GtkWidget *
widget)
{
GtkWidget *
pQuestion;
pQuestion =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_YES_NO,
"
Voulez vous vraiment
\n
"
"
quitter le programme?
"
);
switch
(
gtk_dialog_run
(
GTK_DIALOG
(
pQuestion)))
{
case
GTK_RESPONSE_YES:
gtk_main_quit
(
);
break
;
case
GTK_RESPONSE_NONE:
case
GTK_RESPONSE_NO:
gtk_widget_destroy
(
pQuestion);
break
;
}
}
void
OnAbout
(
gpointer data, guint callback_action,GtkWidget *
widget)
{
GtkWidget *
pAbout;
pAbout =
gtk_message_dialog_new
(
GTK_WINDOW
(
data),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Cours GTK+ 2.0
\n
"
"
http://gtk.developpez.com
"
);
gtk_dialog_run
(
GTK_DIALOG
(
pAbout));
gtk_widget_destroy
(
pAbout);
}
Résultat :
XIV-D. En savoir plus▲
XIV-D-1. Les signaux▲
Prototypes fonctions callback :
GtkMenuShell
-
activate-current
Sélectionnezvoid
user_function
(
GtkMenuShell*
menushell, gboolean force_hide, gpointer user_data); -
cancel
Sélectionnezvoid
user_function
(
GtkMenuShell*
menushell, gpointer user_data); -
cycle-focus
Sélectionnezvoid
user_function
(
GtkMenuShell*
menushell, GtkDirectionType arg1, gpointer user_data); -
deactivate
Sélectionnezvoid
user_function
(
GtkMenuShell*
menushell, gpointer user_data); -
move-current
Sélectionnezvoid
user_function
(
GtkMenuShell*
menushell, GtkMenuDirectionType direction, gpointer user_data); - selection-done
void
user_function
(
GtkMenuShell *
menushell, gpointer user_data);
GtkMenuItem
-
activate
Sélectionnezvoid
user_function
(
GtkMenuItem*
menuitem, gpointer user_data); -
activate-item
Sélectionnezvoid
user_function
(
GtkMenuItem*
menuitem, gpointer user_data); -
toggle-size-allocate
Sélectionnezvoid
user_function
(
GtkMenuItem*
menuitem, gint arg1, gpointer user_data); - toggle-size-request
void
user_function
(
GtkMenuItem *
menuitem, gint arg1, gpointer user_data);
XIV-D-2. Fonctions non documentées▲
GtkMenuShell
void
gtk_menu_shell_insert
(
GtkMenuShell *
menu_shell, GtkWidget *
child, gint position);
void
gtk_menu_shell_deactivate
(
GtkMenuShell *
menu_shell);
void
gtk_menu_shell_select_item
(
GtkMenuShell *
menu_shell, GtkWidget *
menu_item);
void
gtk_menu_shell_deselect
(
GtkMenuShell *
menu_shell);
void
gtk_menu_shell_activate_item
(
GtkMenuShell *
menu_shell, GtkWidget *
menu_item, gboolean force_deactivate);
GtkMenu
void
gtk_menu_reorder_child
(
GtkMenu *
menu, GtkWidget *
child, gint position);
void
gtk_menu_popup
(
GtkMenu *
menu, GtkWidget *
parent_menu_shell, GtkWidget *
parent_menu_item, GtkMenuPositionFunc func, gpointer data, guint button, guint32 activate_time);
void
gtk_menu_set_accel_group
(
GtkMenu *
menu, GtkAccelGroup *
accel_group);
GtkAccelGroup*
gtk_menu_get_accel_group
(
GtkMenu *
menu);
void
gtk_menu_set_accel_path
(
GtkMenu *
menu, const
gchar *
accel_path);
void
gtk_menu_set_title
(
GtkMenu *
menu, const
gchar *
title);
G_CONST_RETURN gchar*
gtk_menu_get_title
(
GtkMenu *
menu);
GtkWidget*
gtk_menu_get_active
(
GtkMenu *
menu);
void
gtk_menu_set_active
(
GtkMenu *
menu, guint index);
void
gtk_menu_set_tearoff_state
(
GtkMenu *
menu, gboolean torn_off);
void
gtk_menu_attach_to_widget
(
GtkMenu *
menu, GtkWidget *
attach_widget, GtkMenuDetachFunc detacher);
void
gtk_menu_detach
(
GtkMenu *
menu);
GtkWidget*
gtk_menu_get_attach_widget
(
GtkMenu *
menu);
GtkMenuItem
void
gtk_menu_item_set_right_justified
(
GtkMenuItem *
menu_item, gboolean right_justified);
void
gtk_menu_item_set_accel_path
(
GtkMenuItem *
menu_item, const
gchar *
accel_path);
void
gtk_menu_item_remove_submenu
(
GtkMenuItem *
menu_item);
void
gtk_menu_item_select
(
GtkMenuItem *
menu_item);
void
gtk_menu_item_deselect
(
GtkMenuItem *
menu_item);
void
gtk_menu_item_activate
(
GtkMenuItem *
menu_item);
void
gtk_menu_item_toggle_size_request
(
GtkMenuItem *
menu_item, gint *
requisition);
void
gtk_menu_item_toggle_size_allocate
(
GtkMenuItem *
menu_item, gint allocation);
gboolean gtk_menu_item_get_right_justified
(
GtkMenuItem *
menu_item);
GtkWidget*
gtk_menu_item_get_submenu
(
GtkMenuItem *
menu_item);
XV. La barre d'outils▲
La barre d'outils est très utile pour placer en dessous du menu les commandes les plus utilisées comme faire/défaire, nouveau, ouvrir, sauvegarde, etc. Un widget, GtkToolbar, indispensable pour une bonne application.
XV-A. Utiliser une GtkToolbar▲
XV-A-1. Création▲
Comme pour tous les autres widgets, c'est très simple :
GtkWidget*
gtk_toolbar_new
(
void
);
XV-A-2. Insertion d'éléments▲
GtkToolbar étant un container, après l'avoir créée, il va falloir ajouter des widget dedans. Cela se divise en deux catégories :
- les widgets habituels comme les GtkButton, GtkToggleButton, GtkRadio pour lesquels GtkToolbar fournit des fonctions qui s'occupent de la création de ces derniers ;
- les autres widgets que nous pouvons ajouter, mais c'est à nous de fournir les widgets donc il faudra les créer auparavant.
Voici les premières fonctions qui permettent d'ajouter un bouton avec du texte et (ou) une icône :
GtkWidget*
gtk_toolbar_append_item
(
GtkToolbar *
toolbar, const
char
*
text, const
char
*
tooltip_text, const
char
*
tooltip_private_text,
GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data);
GtkWidget*
gtk_toolbar_prepend_item
(
GtkToolbar *
toolbar, const
char
*
text, const
char
*
tooltip_text, const
char
*
tooltip_private_text,
GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data);
GtkWidget*
gtk_toolbar_insert_item
(
GtkToolbar *
toolbar, const
char
*
text, const
char
*
tooltip_text,const
char
*
tooltip_private_text,
GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data, gint position);
La première fonction ajoute un bouton à la suite des autres boutons, la seconde l'ajoute en première position et la dernière à une position spécifique.
Pour chaque fonction, le premier paramètre est la barre d'outils dans laquelle on veut ajouter un élément. Il faut comme d'habitude utiliser une macro de conversion qui cette fois est GTK_TOOLBAR().
Ensuite, le paramètre text n'est autre que le label du bouton. Le troisième paramètre, tooltip_text, est une aide qui s'affichera lorsque l'utilisateur laisse le pointeur de sa souris quelques secondes sur le bouton. Le paramètre suivant, tooltip_private_text, n'est plus utilisé, car la partie qui gère ce paramètre est obsolète. Il faut donc mettre ce paramètre à NULL.
Le paramètre icon est là pour définir l'image qui sera associée au bouton.
Les deux paramètres servent à connecter une fonction callback au clic sur le bouton. Le paramètre callback est en fait le nom de la fonction callback et user_data est la donnée supplémentaire à passer à la fonction callback.
Et pour terminer, la fonction gtk_toolbar_insert_item possède un paramètre supplémentaire position qui détermine à quelle position le bouton doit être ajouté. Si cette valeur est soit trop grande, soit négative, cette fonction aura le même effet que gtk_toolbar_append_item.
Ensuite il est possible de créer des éléments selon un type de widget prédéfini, comme GtkRadioButton, GtkToggleButton, GtkButton :
GtkWidget*
gtk_toolbar_append_element
(
GtkToolbar *
toolbar, GtkToolbarChildType type, GtkWidget *
widget, const
char
*
text,
const
char
*
tooltip_text, const
char
*
tooltip_private_text, GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data);
GtkWidget*
gtk_toolbar_prepend_element
(
GtkToolbar *
toolbar, GtkToolbarChildType type, GtkWidget *
widget, const
char
*
text,
const
char
*
tooltip_text, const
char
*
tooltip_private_text, GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data);
GtkWidget*
gtk_toolbar_insert_element
(
GtkToolbar *
toolbar, GtkToolbarChildType type, GtkWidget *
widget, const
char
*
text,
const
char
*
tooltip_text, const
char
*
tooltip_private_text, GtkWidget *
icon, GtkSignalFunc callback, gpointer user_data, gint position);
La majorité des paramètres de ces fonctions ont été détaillés précédemment, nous n'allons donc étudier que les nouveaux.
Tout d'abord, le paramètre type permet de définir le type de widget que nous allons ajouter, et peut prendre une de ces valeurs :
- GTK_TOOLBAR_CHILD_SPACE pour ajouter un espace ;
- GTK_TOOLBAR_CHILD_BUTTON pour ajouter un GtkButton ;
- GTK_TOOLBAR_CHILD_TOGGLEBUTTON pour ajouter un GtkToggleButton ;
- GTK_TOOLBAR_CHILD_RADIOBUTTON pour ajouter un GtkRadioButton ;
- GTK_TOOLBAR_CHILD_WIDGET pour ajouter un widget quelconque.
Il y a ensuite le paramètre widget qui doit être utilisé dans deux cas. Le premier cas est bien entendu, si nous ajoutons un élément de type GTK_TOOLBAR_CHILD_WIDGET. Alors widget sera en fait le widget que nous voulons ajouter.
Le deuxième cas est si nous ajoutons un élément de type GTK_TOOLBAR_CHILD_RADIOBUTTON. Nous avons vu que les GtkRadioButton fonctionnaient par groupe, alors dans ce cas, pour grouper les boutons radio le paramètre widget doit être un GtkRadioButton ajouté précédemment pour que GTK+ puisse les grouper. Bien sûr, s'il s'agit du premier GtkRadioButton, il faut mettre widget à NULL.
Dans tous les autres cas, le paramètre widget doit obligatoirement être à NULL.
Et maintenant, voilà les fonctions pour ajouter n'importe quel type de widget :
void
gtk_toolbar_append_widget
(
GtkToolbar *
toolbar, GtkWidget *
widget, const
char
*
tooltip_text, const
char
*
tooltip_private_text);
void
gtk_toolbar_prepend_widget
(
GtkToolbar *
toolbar, GtkWidget *
widget, const
char
*
tooltip_text, const
char
*
tooltip_private_text);
void
gtk_toolbar_insert_widget
(
GtkToolbar *
toolbar, GtkWidget *
widget, const
char
*
tooltip_text, const
char
*
tooltip_private_text, gint position);
Cette fois, tout est simple, le paramètre widget est simplement le widget que nous voulons ajouter. Il faudra tout de même connecter manuellement les signaux du widget ajouté.
Pour finir, il est possible d'utiliser les GtkStockItem pour créer un bouton. Voici la fonction qui permet cela :
GtkWidget*
gtk_toolbar_insert_stock
(
GtkToolbar *
toolbar, const
gchar *
stock_id, const
char
*
tooltip_text, const
char
*
tooltip_private_text,
GtkSignalFunc callback, gpointer user_data, gint position);
Le paramètre stock_id est tout simplement l'identifiant du GtkStockItem qui figurera sur le bouton.
XV-A-3. Les espaces▲
Nous avons déjà vu que les fonctions de type gtk_toolbar_*_element permettaient d'ajouter un espace pour rendre plus claire la barre d'outils. Il existe en plus de cela trois autres fonctions :
void
gtk_toolbar_append_space
(
GtkToolbar *
toolbar );
void
gtk_toolbar_prepend_space
(
GtkToolbar *
toolbar );
void
gtk_toolbar_insert_space
(
GtkToolbar *
toolbar, guint pos );
Comme d'habitude la première fonction ajoute un espace à la suite des autres éléments, la deuxième au tout début de la barre d'outils et la troisième à une position particulière.
Pour supprimer un espace de la barre d'outils, il existe cette fonction :
void
gtk_toolbar_remove_space
(
GtkToolbar *
toolbar, guint pos);
XV-A-4. Orientation de la barre d'outils▲
La barre d'outils peut être orientée verticalement ou horizontalement et cela à n'importe quel moment a l'aide de cette fonction :
void
gtk_toolbar_set_orientation
(
GtkToolbar *
toolbar, GtkOrientation orientation) ;
Le paramètre orientation peut prendre deux valeurs :
- GTK_ORIENTATION_HORIZONTAL ;
- GTK_ORIENTATION_VERTICAL.
Et, cette fonction permet de connaître l'orientation de la barre d'outils :
GtkOrientation gtk_toolbar_get_oritentation
(
GtkToolbar *
toolbar);
XV-A-5. Les styles▲
Il est possible de changer la façon d'afficher certains éléments de la barre d'outils : afficher que le texte, seulement les icônes ou les deux. Voilà la fonction qui permet de contrôler cela :
void
gtk_toolbar_set_style
(
GtkToolbar *
toolbar, GtkToolbarStyle style) ;
Le paramètre style peut prendre quatre valeurs différentes :
- GTK_TOOLBAR_ICONS pour n'afficher que l'icône ;
- GTK_TOOLBAR_TEXT pour n'afficher que le texte ;
- GTK_TOOLBAR_BOTH pour afficher le texte en dessous de l'icône (valeur par défaut) ;
- GTK_TOOLBAR_BOTH_HORIZ pour afficher le texte à côté de l'icône.
Et pour finir, cette fonction permet de connaître le style de la barre d'outils :
GtkToolbarStyle gtk_toolbar_get_style
(
GtkToolbar *
toolbar);
XV-A-6. La taille des icônes▲
Enfin pour terminer, GTK+ nous offre la possibilité de modifier la taille des icônes de la barre d'outils avec cette fonction :
void
gtk_toolbar_set_icon_size
(
GtkToolbar *
toolbar, GtkIconSize icon_size);
Le paramètre icon_size est du type GtkIconSize que nous avons déjà rencontré dans le chapitre sur les images. Nous allons tout de même rappeler les différentes valeurs possibles qui sont les suivantes :
- GTK_ICON_SIZE_MENU ;
- GTK_ICON_SIZE_SMALL_TOOLBAR ;
- GTK_ICON_SIZE_LARGE_TOOLBAR (valeur par défaut) ;
- GTK_ICON_SIZE_BUTTON ;
- GTK_ICON_SIZE_DND ;
- GTK_ICON_SIZE_DIALOG.
Et bien sûr, pour connaître la taille des icônes, nous avons la fonction :
GtkIconSize gtk_toolbar_get_icon_size
(
GtkToolbar *
toolbar);
XV-A-7. 1.7 Exemple▲
Dans cet exemple, nous allons juste créer une barre d'outils dans laquelle nous allons ajouter quelques boutons dont deux d'entre eux permettront de changer l'orientation de la barre d'outils.
XV-A-8. 1.8 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnChangeOrientation
(
GtkWidget *
widget, gpointer data);
static
GtkWidget *
pToolbar =
NULL
;
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
gtk_init
(&
argc, &
argv);
/* Création de la fenêtre */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkToolbar
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
/* Création de la barre d'outils */
pToolbar =
gtk_toolbar_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pToolbar, FALSE, FALSE, 0
);
/* Création à partir de stock */
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_NEW,
"
Nouveau
"
,
NULL
,
NULL
,
NULL
,
-
1
);
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_OPEN,
"
Ouvrir
"
,
NULL
,
NULL
,
NULL
,
-
1
);
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_SAVE,
"
Enregistrer
"
,
NULL
,
NULL
,
NULL
,
-
1
);
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_QUIT,
"
Fermer
"
,
NULL
,
G_CALLBACK
(
gtk_main_quit),
NULL
,
-
1
);
/* Insertion d'un espace */
gtk_toolbar_append_space
(
GTK_TOOLBAR
(
pToolbar));
/* Création à partir de stock */
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_GO_FORWARD,
"
Horizontale
"
,
NULL
,
G_CALLBACK
(
OnChangeOrientation),
GINT_TO_POINTER
(
GTK_ORIENTATION_HORIZONTAL),
-
1
);
gtk_toolbar_insert_stock
(
GTK_TOOLBAR
(
pToolbar),
GTK_STOCK_GO_DOWN,
"
Verticale
"
,
NULL
,
G_CALLBACK
(
OnChangeOrientation),
GINT_TO_POINTER
(
GTK_ORIENTATION_VERTICAL),
-
1
);
/* Modification de la taille des icônes */
gtk_toolbar_set_icon_size
(
GTK_TOOLBAR
(
pToolbar),
GTK_ICON_SIZE_BUTTON);
/* Affichage uniquement des icônes */
gtk_toolbar_set_style
(
GTK_TOOLBAR
(
pToolbar),
GTK_TOOLBAR_ICONS);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnChangeOrientation
(
GtkWidget *
widget, gpointer data)
{
/* Modification de l'orientation */
gtk_toolbar_set_orientation
(
GTK_TOOLBAR
(
pToolbar),
GPOINTER_TO_INT
(
data));
}
Résultat :
XV-B. En savoir plus▲
XV-B-1. Fonctions documentées▲
void
gtk_toolbar_set_tooltips
(
GtkToolbar *
toolbar, gboolean enable);
Permet de définir s'il faut afficher l'aide.
Entrée(s) :
- toolbar : la barre d'outils
- enable : TRUE pour afficher l'aide, FALSE sinon.
Sortie : rien
gboolean gtk_toolbar_get_tooltips
(
GtkToolbar *
toolbar);
Pour savoir si le programme affiche l'aide.
Entrée(s) :
- toolbar : la barre d'outils
Sortie : TRUE si l'aide est affichable, FALSE sinon.
void
gtk_toolbar_unset_icon_size
(
GtkToolbar *
toolbar);
Change la taille des icônes en la remettant à la valeur par défaut.
Entrée(s) :
- toolbar : la barre d'outils
Sortie : rien
void
gtk_toolbar_unset_style
(
GtkToolbar *
toolbar);
Change le style de la barre d'outils en le remettant à la valeur par défaut.
Entrée(s) :
- toolbar : la barre d'outils
Sortie : rien
XVI. La barre d'état▲
La barre d'état peut avoir plusieurs utilités. Tout d'abord lorsqu'un programme est en train d'effectuer une action, elle peut servir à signaler à l'utilisateur ce que le programme fait. Elle peut aussi servir à expliquer l'utilité d'un bouton (ou d'un élément du menu). Nous allons étudier en détail le fonctionnement de ce widget nommé GtkStatusBar.
XVI-A. Utilisation d'une GtkStatusBar▲
XVI-A-1. Création▲
La création de ce widget est aussi simple que pour tous les autres widgets. Il suffit d'utiliser cette fonction :
GtkWidget *
gtk_statusbar_new
(
void
);
XVI-A-2. Utilisation▲
Regardons tout d'abord comment fonctionne une GtkStatusBar. Les messages sont mis dans une pile, l'élément le plus haut de la pile étant affiché. Pour gérer cette pile, Gtk+ offre trois fonctions différentes.
Mais avant de pouvoir gérer cette pile, il faut connaître l'identifiant de la partie du programme qui ajoute un message dans la pile :
guint gtk_statusbar_get_context_id
(
GtkStatusbar *
statusbar, const
gchar *
context_description);
Cette fonction va automatiquement ajouter un contexte, et renvoyer la valeur correspondante. Par la suite cet identifiant est à utiliser pour ajouter ou enlever des éléments à la pile.
Pour ajouter un élément, il n'y a qu'une seule fonction :
guint gtk_statusbar_push
(
GtkStatusbar *
statusbar, guint context_id, const
gchar *
text);
- statusbar : pointeur sur la barre d'état précédemment créée.
- ontext_id : identifiant origine message.
- text : message à afficher.
Après l'appel de cette fonction, le message est automatiquement ajouté en haut de la pile et est affiché dans la barre d'état. La valeur de retour correspond à l'identifiant du message dans la pile qui peut être utile pour sa suppression.
Pour supprimer un message de la pile, nous avons cette fois deux fonctions différentes :
void
gtk_statusbar_pop
(
GtkStatusbar *
statusbar, guint context_id);
void
gtk_statusbar_remove
(
GtkStatusbar *
statusbar, guint context_id, guint message_id);
La première fonction enlève l'élément le plus haut placé dans la pile provenant de la partie du programme ayant l'identifiant context_id. C'est là que context_id prend toute son importance.
La deuxième fonction enlève l'élément par son identifiant et celui de son contexte.
Nous avons maintenant tout ce qu'il faut pour utiliser une barre d'état dans notre application.
XVI-A-3. 1.3 Exemple▲
Nous allons construire une application comportant deux boutons et barre d'état. Le but de cette application et d'afficher un message dans la barre d'état lorsque la souris survole un des boutons.
Nous allons d'abord créer notre barre d'état :
StatusBar =
gtk_status_bar_new
(
);
Ensuite nous allons l'insérer dans la fenêtre principale. En général, la barre d'état se trouve en bas d'une fenêtre, nous allons donc utiliser la fonction gtk_box_pack_end :
gtk_box_pack_end
(
GTK_BOX
(
VBox),StatusBar,FALSE,FALSE,0
);
Nous allons créer deux contextes différents (un pour chaque bouton) pour l'utilisation de la barre d'état :
ContextId1 =
gtk_statusbar_get_context_id
(
GTK_STATUSBAR
(
StatusBar), "
ExitMsg
"
);
ContextId2 =
gtk_statusbar_get_context_id
(
GTK_STATUSBAR
(
StatusBar), "
AboutMsg
"
);
Il ne reste plus qu'à connecter les signaux « enter » et « leave » de deux boutons et écrire les fonctions callback. Dans la fonction de connexion, le ContextIdx sera passé en paramètre data, mais il faudra utiliser la macro de conversion GINT_TO_POINTER().
XVI-A-4. 1.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
static
GtkWidget *
pStatusBar;
void
OnAboutBtn
(
GtkWidget *
pButton, GtkWidget *
pWindow);
void
OnExitBtnEnter
(
GtkWidget *
pButton, gpointer iContextId);
void
OnAboutBtnEnter
(
GtkWidget *
pButton, gpointer iContextId);
void
ClearStatus
(
GtkWidget *
pButton, gpointer iContextId);
int
main
(
int
argc, char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget*
pVBox;
GtkWidget*
pExitButton;
GtkWidget *
pAboutButton;
guint iContextId1;
guint iContextId2;
gtk_init
(&
argc, &
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkStatusbar
"
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox=
gtk_vbox_new
(
FALSE,5
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
pExitButton=
gtk_button_new_with_label
(
"
Quitter
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pExitButton, TRUE, FALSE, 5
);
g_signal_connect
(
G_OBJECT
(
pExitButton), "
clicked
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pAboutButton=
gtk_button_new_with_label
(
"
À propos...
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pAboutButton, TRUE, FALSE, 5
);
g_signal_connect
(
G_OBJECT
(
pAboutButton), "
clicked
"
, G_CALLBACK
(
OnAboutBtn), pWindow);
/* Création de la barre d'état */
pStatusBar =
gtk_statusbar_new
(
);
gtk_box_pack_end
(
GTK_BOX
(
pVBox), pStatusBar, FALSE, FALSE, 0
);
/* Création des contextes */
iContextId1 =
gtk_statusbar_get_context_id
(
GTK_STATUSBAR
(
pStatusBar), "
ExitMsg
"
);
iContextId2 =
gtk_statusbar_get_context_id
(
GTK_STATUSBAR
(
pStatusBar), "
AboutMsg
"
);
g_signal_connect
(
G_OBJECT
(
pExitButton), "
enter
"
, G_CALLBACK
(
OnExitBtnEnter),
GINT_TO_POINTER
(
iContextId1));
g_signal_connect
(
G_OBJECT
(
pAboutButton), "
enter
"
, G_CALLBACK
(
OnAboutBtnEnter),
GINT_TO_POINTER
(
iContextId2));
g_signal_connect
(
G_OBJECT
(
pExitButton), "
leave
"
, G_CALLBACK
(
ClearStatus),
GINT_TO_POINTER
(
iContextId1));
g_signal_connect
(
G_OBJECT
(
pAboutButton), "
leave
"
, G_CALLBACK
(
ClearStatus),
GINT_TO_POINTER
(
iContextId2));
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnAboutBtn
(
GtkWidget *
pButton, GtkWidget *
pWindow)
{
GtkWidget *
pAboutDlg;
pAboutDlg =
gtk_message_dialog_new
(
GTK_WINDOW
(
pWindow),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Cours GTK+ 2.0
\n
"
"
GtkStatusbar
\n
"
"
http://gtk.developpez.com
"
);
gtk_dialog_run
(
GTK_DIALOG
(
pAboutDlg));
gtk_widget_destroy
(
pAboutDlg);
}
void
OnExitBtnEnter
(
GtkWidget *
pButton, gpointer iContextId)
{
/* Ajout d'un message */
gtk_statusbar_push
(
GTK_STATUSBAR
(
pStatusBar), GPOINTER_TO_INT
(
iContextId), "
Quitter l'application
"
);
}
void
OnAboutBtnEnter
(
GtkWidget *
pButton, gpointer iContextId)
{
/* Ajout d'un message */
gtk_statusbar_push
(
GTK_STATUSBAR
(
pStatusBar), GPOINTER_TO_INT
(
iContextId), "
Informations
"
);
}
void
ClearStatus
(
GtkWidget *
pButton, gpointer iContextId)
{
/* Suppression d'un message */
gtk_statusbar_pop
(
GTK_STATUSBAR
(
pStatusBar), GPOINTER_TO_INT
(
iContextId));
}
Résultat :
XVI-B. En savoir plus▲
XVI-B-1. Signaux▲
Prototypes fonctions callback :
-
text-popped
-
Ce signal est émis par la barre d'état lorsqu'un message est supprimé.
Sélectionnezvoid
user_function
(
GtkStatusbar*
statusbar, guint context_id, gchar*
text, gpointer user_data);
-
-
text-pushed
- Ce signal est émis par la barre d'état lorsqu'un message est ajouté.
void
user_function
(
GtkStatusbar *
statusbar, guint context_id, gchar *
text, gpointer user_data);
XVI-B-2. Fonctions documentées▲
void
gtk_statusbar_set_has_resize_grip
(
GtkStatusbar *
statusbar, gboolean setting);
Définit si la zone à droite de la barre permet de redimensionner la fenêtre conteneur.
Entrée(s) :
- statusbar : la barre d'état.
- setting : TRUE pour oui, FALSE sinon.
Sortie : rien.
gboolean gtk_statusbar_get_has_resize_grip
(
GtkStatusbar *
statusbar);
Pour savoir si la barre d'état permet de redimensionner la fenêtre conteneur.
Entrée(s) :
- statusbar : la barre d'état.
Sortie : TRUE si oui, FALSE sinon.
XVII. La sélection de valeurs numériques▲
Nous allons dans ce chapitre étudier trois widgets différents qui vont nous permettre de définir une valeur numérique sans avoir à la saisir au clavier. Le premier widget que nous allons étudier est GtkScrollbar qui se dérive en deux widgets différents, un qui est vertical et l'autre horizontal. Puis nous étudierons le widget GtkScale qui lui aussi se décline en un widget vertical et un horizontal. Et nous terminerons avec le widget GtkSpinButton.
XVII-A. Introduction▲
Ces trois widgets permettent de choisir une valeur numérique à l'intérieur d'une fourchette de valeurs bien définies. Le fonctionnement similaire de ces trois widgets est rendu possible par l'utilisation de l'objet GtkAdjustment. Nous allons donc tout d'abord acquérir les notions nécessaires sur ce widget pour comprendre les widgets de sélection.
XVII-A-1. Structure de l'objet GtkAdjustment▲
struct
_GtkAdjustment
{
GtkObject parent_instance;
gdouble lower;
gdouble upper;
gdouble value;
gdouble step_increment;
gdouble page_increment;
gdouble page_size;
}
La propriété parent_instance nous dit tout simplement que l'objet GtkAdjustment dérive directement de GtkObject. Les valeurs lower et upper déterminent respectivement la valeur minimale et la valeur maximale que peut prendre le widget qui utilise cet objet. La valeur value donne la valeur actuelle telle qu'elle est définie par le widget. Les valeurs step_increment et page_increment définissent de combien value sera modifiée à chaque fois que l'utilisateur demande d'augmenter ou de diminuer la valeur. Nous verrons la différence entre ces deux valeurs avec l'étude des widgets GtkScrollbar et GtkScale. La dernière propriété page_size définit la taille d'une page, mais là aussi cela deviendra plus clair avec l'étude des widgets qui va suivre.
XVII-A-2. Les fonctions de base▲
La première fonction de base est bien sûr la fonction qui permet de créer un tel objet :
GtkObject*
gtk_adjustment_new
(
gdouble value, gdouble lower, gdouble upper, gdouble step_increment, gdouble page_increment, gdouble page_size);
Nous retrouvons ici tous les paramètres définis précédemment.
Ensuite pour modifier ou récupérer la valeur actuelle de l'objet, il y a ces deux fonctions :
void
gtk_adjustment_set_value
(
GtkAdjustment *
adjustment, gdouble value);
gdouble gtk_adjustment_get_value
(
GtkAdjustment *
adjustment);
Bien entendu la première fonction change le widget utilisateur pour que sa position représente la valeur value, et la deuxième fonction récupère cette valeur.
Et pour terminer, voici la fonction qui permet de modifier les valeurs limites de l'objet :
void
gtk_adjustment_clamp_page
(
GtkAdjustment *
adjustment, gdouble lower, gdouble upper);
Nous avons vu l'essentiel des fonctions de l'objet GtkAdjustment, mais en règle générale, il n'est pas nécessaire de les utiliser, car les widgets qui nécessitent cet objet ont leurs propres fonctions d'accès et de modification des paramètres.
XVII-B. Le widget GtkScrollbar▲
Comme nous l'avons dit dans la présentation, ce widget se décline en deux variantes différentes :
- Une horizontale avec le widget GtkHScrollbar ;
- Une verticale avec le widget GtkVScrollbar.
Mais nous allons voir que mis à part les fonctions de création, toutes les autres opérations se font avec les mêmes fonctions, quel que soit le widget utilisé.
XVII-B-1. Création d'une GtkScrollbar▲
Voici donc les deux fonctions de création disponibles :
GtkWidget*
gtk_vscrollbar_new
(
GtkAdjustment *
adjustment);
GtkWidget*
gtk_hscrollbar_new
(
GtkAdjustment *
adjustment);
La première fonction crée donc une GtkVScrollbar et la seconde une GtkHScrollbar. De plus, nous voyons qu'il faut obligatoirement un GtkAdjustment pour définir les paramètres du widget. Il va donc falloir dans un premier temps créer un GtkAdjustment et définir ses valeurs.
Pour ce qui est des valeurs lower, upper, et value, il n'y a pas de problème. Par contre pour les valeurs step_increment et page_increment, il faut connaître un peu le fonctionnement de ce widget. Regardons d'abord à quoi ressemble un widget GtkHScrollbar.
La zone 1 est en fait l'afficheur de la valeur actuelle prise par la GtkScrollbar. Elle permet aussi de sélectionner une valeur en le déplaçant à l'aide de la souris. Les deux zones 2 permettent de modifier la valeur de la zone 1. Un clic de souris sur une de ces zones modifiera la valeur de plus ou moins la valeur de step_increment. Les zones 3 ont le même objectif que les zones 2, mais cette fois avec une modification de valeur de page_increment.
Il reste encore le dernier paramètre à configurer. Ce dernier, page_size, détermine la taille de la zone 1. Si, par exemple le widget GtkScrollbar a une valeur minimale de 0 et une valeur maximale de 100, et nous définissons page_size comme ayant une valeur de 50, la zone 1 du widget aura une longueur égale à la moitié de celle du widget. Le dernier point sur ce paramètre est qu'il détermine aussi la valeur qu'il faut donner à upper. Ce widget fonctionnant en utilisant des pages, la valeur upper n'est jamais atteinte. Si l'on veut pouvoir choisir une valeur entre 0 et 100 avec un page_size égal à 50, il faudra mettre upper à 150 soit l'upper théorique plus page_size.
En effet, ce widget n'a pas comme vocation première de permettre de sélectionner des valeurs numériques, mais plutôt l'affichage d'autre widget dont la hauteur (ou la largeur) est supérieure à la zone d'affichage. Ainsi lorsque la barre de sélection est complètement à gauche, la valeur de la GtkScrollbar est bien de 0, mais elle considère qu'elle affiche une zone allant de 0 à page_size (50 dans notre exemple). De ce fait, si la barre de sélection est complètement à droite la valeur de la GtkScrollbar sera égale à upper-page_size et considérera qu'elle affiche une zone allant d'upper-page_size à upper (50 à 100 dans notre exemple). Pour conclure, il faut toujours donner à upper la valeur maximale que nous souhaitons pouvoir sélectionner plus la valeur de page_size.
Nous savons maintenant comment configurer le GtkAdjustment afin de créer proprement une GtkScrollbar.
XVII-B-2. La gestion des valeurs▲
Nous allons maintenant traiter les fonctions de gestion d'une GtkScrollbar. Pour cela, nous n'allons pas utiliser les widgets GtkHScrollbar et GtkVScrollbar, car il n'y a pour chaque widget qu'une seule fonction de création ni le widget GtkScrollbar, car il ne possède aucune fonction, mais le widget GtkRange dont dérive toute cette panoplie.
Tout d'abord pour fixer la valeur d'une GtkScrollbar, nous avons à notre disposition la fonction suivante :
void
gtk_range_set_value
(
GtkRange *
range, gdouble value);
Bien sûr le premier paramètre est la GtkScrollbar dont nous voulons fixer la valeur. Il faut pour cela utiliser la macro de conversion GTK_RANGE(). Le deuxième paramètre est la valeur que nous voulons donner à notre GtkScrollbar.
À l'inverse, la fonction nous permettant de connaître la valeur de la GtkScrollbar est :
gdouble gtk_range_get_value
(
GtkRange *
range);
Ensuite le widget GtkRange nous offre la possibilité de modifier les bornes du widget ainsi que les différents pas avec ces deux fonctions :
void
gtk_range_set_increments
(
GtkRange *
range, gdouble step, gdouble page);
void
gtk_range_set_range
(
GtkRange *
range, gdouble min, gdouble max);
La première fonction modifie les pas de modification. Les paramètres step et page correspondent aux paramètres step_increment et page_increment du GtkAdjustment associé au widget.
La deuxième fonction permet de modifier les valeurs minimale et maximale que le widget peut prendre. Là encore, il faut penser au problème de la valeur maximale pour bien configurer max.
Une autre possibilité pour modifier ces paramètres est de créer un nouveau GtkAdjustment et de l'associer à la GtkScrollbar avec cette fonction :
void
gtk_range_set_adjustment
(
GtkRange *
range, GtkAdjustment *
adjustment);
XVII-B-3. Exemple▲
Notre premier exemple de ce chapitre va nous permettre de sélection les valeurs RGB que nous souhaitons affecter. La couleur formée par ces valeurs ne sera pas affichée, car nous nous contenterons d'afficher ces valeurs dans un label.
Pour modifier les valeurs des labels en fonction des modifications des GtkScrollbar, nous allons capturer le signal « value-changed » de chaque GtkScrollbar.
XVII-B-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnScrollbarChange
(
GtkWidget *
pWidget, gpointer data);
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget *
pMainVBox;
GtkWidget *
pFrame;
GtkWidget *
pColorBox;
GtkWidget *
pLabel;
GtkWidget *
pScrollbar;
GtkObject *
Adjust;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkScrollbar
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 4
);
pMainVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pMainVBox);
pFrame =
gtk_frame_new
(
"
Rouge
"
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pColorBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pColorBox);
/* Label d'affichage de valeur R*/
pLabel =
gtk_label_new
(
"
0
"
);
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pLabel, FALSE, FALSE, 0
);
/* Création d un GtkAdjustment */
Adjust =
gtk_adjustment_new
(
0
, 0
, 256
, 1
, 10
, 1
);
/* Creation d une scrollbar horizontale*/
pScrollbar =
gtk_hscrollbar_new
(
GTK_ADJUSTMENT
(
Adjust));
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pScrollbar, TRUE, TRUE, 0
);
/* Connexion du signal pour modification de l'affichage */
g_signal_connect
(
G_OBJECT
(
pScrollbar), "
value-changed
"
,
G_CALLBACK
(
OnScrollbarChange), (
GtkWidget*
)pLabel);
/* Idem pour G */
pFrame =
gtk_frame_new
(
"
Vert
"
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pColorBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pColorBox);
pLabel =
gtk_label_new
(
"
0
"
);
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pLabel, FALSE, FALSE, 0
);
Adjust =
gtk_adjustment_new
(
0
, 0
, 256
, 1
, 10
, 1
);
pScrollbar =
gtk_hscrollbar_new
(
GTK_ADJUSTMENT
(
Adjust));
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pScrollbar, TRUE, TRUE, 0
);
g_signal_connect
(
G_OBJECT
(
pScrollbar), "
value-changed
"
,
G_CALLBACK
(
OnScrollbarChange), (
GtkWidget*
)pLabel);
/* Idem pour B */
pFrame =
gtk_frame_new
(
"
Bleu
"
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pColorBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pColorBox);
pLabel =
gtk_label_new
(
"
0
"
);
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pLabel, FALSE, FALSE, 0
);
Adjust =
gtk_adjustment_new
(
0
, 0
, 256
, 1
, 10
, 1
);
pScrollbar =
gtk_hscrollbar_new
(
GTK_ADJUSTMENT
(
Adjust));
gtk_box_pack_start
(
GTK_BOX
(
pColorBox), pScrollbar, TRUE, TRUE, 0
);
g_signal_connect
(
G_OBJECT
(
pScrollbar), "
value-changed
"
,
G_CALLBACK
(
OnScrollbarChange), (
GtkWidget*
)pLabel);
gtk_widget_show_all
(
pWindow);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnScrollbarChange
(
GtkWidget *
pWidget, gpointer data)
{
gchar*
sLabel;
gint iValue;
/* Récupération de la valeur de la scrollbar */
iValue =
gtk_range_get_value
(
GTK_RANGE
(
pWidget));
/* Création du nouveau label */
sLabel =
g_strdup_printf
(
"
%d
"
, iValue);
/* Modification du label */
gtk_label_set_text
(
GTK_LABEL
(
data), sLabel);
/* Liberation memoire */
g_free
(
sLabel);
}
Résultat :
XVII-C. Le widget GtkScale▲
Les widgets GtkHScale et GtkVScale ont un fonctionnement quasi identique aux widget GtkHScrollbar et GtkVScrollbar, mais sont plus simples d'utilisation. Un des avantages de ce widget est qu'il offre la possibilité d'afficher tout seul sa valeur.
XVII-C-1. Création▲
Comme pour les GtkScrollbar, nous pouvons créer des GtkScale à l'aide de GtkAdjustment avec ces fonctions :
GtkWidget*
gtk_vscale_new
(
GtkAdjustment *
adjustment);
GtkWidget*
gtk_hscale_new
(
GtkAdjustment *
adjustment);
La première fonction crée donc un GtkScale vertical alors la deuxième un GtkScale horizontal.
Mais pour ne pas avoir à créer un objet GtkAdjustment, les créateurs de GTK+ ont pensé à nous fournir une fonction qui n'en a pas besoin :
GtkWidget*
gtk_vscale_new_with_range
(
gdouble min, gdouble max, gdouble step);
GtkWidget*
gtk_hscale_new_with_range
(
gdouble min, gdouble max, gdouble step);
Avec ces quatre fonctions, la signification de step (ou step_increment si l'on utilise un GtkAdjustment) est un peu différente, car le widget GtkScale n'a pas de bouton fléché comme GtkScrollbar. Cette valeur est utilisée pour un déplacement à l'aide des touches fléchées lorsque le widget a le focus. De plus, si nous n'utilisons pas de GtkAdjustment, la valeur de page_increment est égale à dix fois celle de step.
XVII-C-2. La gestion des valeurs▲
Pour récupérer ou fixer les différentes valeurs d'un widget GtkScale il faut, comme pour le widget GtkScrollbar, utiliser les fonctions du widget GtkRange qui ont été décrites plus haut. Nous n'allons donc pas revenir dessus.
XVII-C-3. Affichage de la valeur sous forme de label▲
Comme nous l'avons dit dans la présentation de ce widget, il s'occupe seul d'afficher et de mettre à jour un label qui affiche la valeur du widget. Par défaut, le label est affiché au-dessus du GtkScale. Étudions les quelques fonctions qui nous sont fournies pour gérer cet affichage.
void
gtk_scale_set_draw_value
(
GtkScale *
scale, gboolean draw_value);
gboolean gtk_scale_get_draw_value
(
GtkScale *
scale);
La première fonction nous permet de décider si nous voulons qu'un label s'affiche ou pas. Pour cela il suffit de mettre le paramètre draw_value à TRUE si nous souhaitons qu'il s'affiche ou FALSE si nous ne le souhaitons pas. En ce qui concerne le premier paramètre, il faut utiliser la macro de conversion GTK_SCALE().
La deuxième fonction permet de savoir si le label est affiché ou pas.
Ensuite nous avons la possibilité de gérer le nombre de chiffres après la virgule qui sont affichés :
void
gtk_scale_set_digits
(
GtkScale *
scale, gint digits);
gint gtk_scale_get_digits
(
GtkScale *
scale);
Dans la première fonction, digit est bien sûr le nombre de chiffres après la virgule à afficher.
Et pour terminer, nous allons voir comment gérer la position du label par rapport à la barre de sélection :
void
gtk_scale_set_value_pos
(
GtkScale *
scale, GtkPositionType pos);
GtkPositionType gtk_scale_get_value_pos
(
GtkScale *
scale);
Le paramètre pos (de la première fonction) peut prendre une de ces quatre valeurs :
- GTK_POS_LEFT pour le mettre à gauche ;
- GTK_POS_RIGHT pour le mettre à droite ;
- GTK_POS_TOP pour le mettre au-dessus ;
- GTK_POS_BOTTOM pour le mettre en dessous.
3.4 Exemple▲
Nous allons reprendre l'exemple précédent que nous allons transformer pour l'utilisation de widget GtkHScale ce qui le rendra plus simple. Cependant, pour utiliser les fonctions du widget GtkScale, le premier GtkHScale aura un label au-dessus, le second aura un label en dessous et le troisième pas du tout.
XVII-C-4. 3.5 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget *
pMainVBox;
GtkWidget *
pFrame;
GtkWidget *
pLabel;
GtkWidget *
pScale;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkScale
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 4
);
pMainVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pMainVBox);
pFrame =
gtk_frame_new
(
"
Rouge
"
);
/* Création du widget GtkHScale */
pScale =
gtk_hscale_new_with_range
(
0
, 255
, 1
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pScale);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pFrame =
gtk_frame_new
(
"
Vert
"
);
pScale =
gtk_hscale_new_with_range
(
0
, 255
, 1
);
/* Position du label en dessous */
gtk_scale_set_value_pos
(
GTK_SCALE
(
pScale), GTK_POS_BOTTOM);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pScale);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pFrame =
gtk_frame_new
(
"
Bleu
"
);
pScale =
gtk_hscale_new_with_range
(
0
, 255
, 1
);
/* Pas d'affichage du label */
gtk_scale_set_draw_value
(
GTK_SCALE
(
pScale), FALSE);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pScale);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XVII-D. Le widget GtkSpinButton▲
Ce widget est un peu différent des deux précédents dans le sens ou il s'agit en fait d'un widget GtkEntry et de deux GtkButton assemblés pour former un tout. De plus il permet de sélectionner une valeur soit en utilisant les boutons soit en entrant directement la valeur au clavier. Mais voyons tout cela en détail.
XVII-D-1. Création▲
Il existe là aussi deux fonctions de créations :
GtkWidget*
gtk_spin_button_new
(
GtkAdjustment *
adjustment, gdouble climb_rate, guint digits);
GtkWidget*
gtk_spin_button_new_with_range
(
gdouble min, gdouble max, gdouble step);
La première fonction permet de créer un GtkSpinButton à partir d'un GtkAdjustment, mais il faut cependant préciser le paramètre climb_rate qui correspond au paramètre step_increment du GtkAdjustment et digits qui représente le nombre de chiffres après la virgule de la valeur que nous allons pouvoir sélectionner.
La deuxième fonction permet de se passer de GtkAdjustment, car nous fixons les valeurs minimales et maximales (paramètres min et max) ainsi que la valeur de modification avec le paramètre step. En ce qui concerne le nombre de chiffres après la virgule, il sera identique à celui de step.
Pour ce widget, le clavier permet aussi de modifier sa valeur. Les touches fléchées HAUT et BAS permettent de modifier la valeur de step_increment (dans le cas de l'utilisation d'un GtkAdjustment) ou de step. De plus les touches PAGE_UP et PAGE_DOWN permettent de modifier la valeur de page_increment avec une création utilisant un GtkAdjustment ou de step*10 dans l'autre cas.
XVII-D-2. Gestion des valeurs▲
Voyons tout d'abord comment récupérer ou modifier la valeur en cours d'un GtkSpinButton à l'aide d'une de ces trois fonctions :
void
gtk_spin_button_set_value
(
GtkSpinButton *
spin_button, gdouble value);
gdouble gtk_spin_button_get_value
(
GtkSpinButton *
spin_button);
gint gtk_spin_button_get_value_as_int
(
GtkSpinButton *
spin_button);
La première fonction permet donc de modifier la valeur d'un GtkSpinButton. Il faut pour le premier paramètre utiliser la macro de conversion GTK_SPIN_BUTTON().
La deuxième fonction permet de récupérer la valeur d'un GtkSpinButton tout simplement.
La dernière fonction a le même but que la deuxième, mais celle-ci renvoie un entier alors que la deuxième renvoie un double.
Nous pouvons nous occuper du nombre de chiffres après la virgule avec ces deux fonctions :
guint gtk_spin_button_get_digits
(
GtkSpinButton *
spin_button);
void
gtk_spin_button_set_digits
(
GtkSpinButton *
spin_button, guint digits);
La première fonction permettant de connaître le nombre de chiffre après la virgule alors que la seconde permet de le modifier.
Et pour terminer, voici les fonctions qui permettent de modifier les bornes des valeurs :
void
gtk_spin_button_get_range
(
GtkSpinButton *
spin_button, gdouble *
min, gdouble *
max);
void
gtk_spin_button_set_range
(
GtkSpinButton *
spin_button, gdouble min, gdouble max);
Comme d'habitude, la première fonction permet de connaître les bornes du GtkSpinButton et la seconde permet de les modifier.
Mais bien sûr, tout cela peut se modifier à l'aide des GtkAdjustment avec ces deux fonctions :
GtkAdjustment*
gtk_spin_button_get_adjustment
(
GtkSpinButton *
spin_button);
void
gtk_spin_button_set_adjustment
(
GtkSpinButton *
spin_button, GtkAdjustment *
adjustment);
XVII-D-3. Exemple▲
Le programme exemple sera identique aux deux premiers, c'est-à-dire qu'il va permettre de sélectionner une valeur RGB à l'aide de trois widgets GtkSpinButton.
XVII-D-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget *
pMainVBox;
GtkWidget *
pFrame;
GtkWidget *
pSpin;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkSpinButton
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 4
);
pMainVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pMainVBox);
pFrame =
gtk_frame_new
(
"
Rouge
"
);
/* Création du widget GtkSpinButton */
pSpin =
gtk_spin_button_new_with_range
(
0
, 255
, 1
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pSpin);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pFrame =
gtk_frame_new
(
"
Vert
"
);
pSpin =
gtk_spin_button_new_with_range
(
0
, 255
, 1
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pSpin);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
pFrame =
gtk_frame_new
(
"
Bleu
"
);
pSpin =
gtk_spin_button_new_with_range
(
0
, 255
, 1
);
gtk_container_add
(
GTK_CONTAINER
(
pFrame), pSpin);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pFrame, FALSE, FALSE, 0
);
gtk_widget_show_all
(
pWindow);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XVII-E. En savoir plus▲
XVII-E-1. Signaux▲
Prototypes fonctions callback :
GtkAdjustment
-
changed
-
Ce signal est émis lorsqu'un paramètre autre que value est modifié.
Sélectionnezvoid
user_function
(
GtkAdjustment*
adjustment, gpointer user_data);
-
-
value-changed
- Ce signal est émis lorsque le paramètre value est modifié.
void
user_function
(
GtkAdjustment *
adjustment, gpointer user_data);
GtkScale
- format-value
gchar*
user_function
(
GtkScale *
scale, gdouble arg1, gpointer user_data);
GtkRange
-
adjust-bounds
Sélectionnezvoid
user_function
(
GtkRange*
range, gdouble arg1, gpointer user_data); -
move-slider
Sélectionnezvoid
user_function
(
GtkRange*
range, GtkScrollType arg1, gpointer user_data); - value-changed
void
user_function
(
GtkRange *
range, gpointer user_data);
GtkSpinButton
-
change-value
Sélectionnezvoid
user_function
(
GtkSpinButton*
spinbutton, GtkScrollType arg1, gpointer user_data); -
input
Sélectionnezgint
user_function
(
GtkSpinButton*
spinbutton, gpointer arg1, gpointer user_data); -
output
Sélectionnezgboolean
user_function
(
GtkSpinButton*
spinbutton, gpointer user_data); - value-changed
gboolean user_function
(
GtkSpinButton *
spinbutton, gpointer user_data);
XVII-E-2. Fonctions non documentées▲
GtkAdjustment
void
gtk_adjustment_changed
(
GtkAdjustment *
adjustment);
void
gtk_adjustment_value_changed
(
GtkAdjustment *
adjustment);
GtkRange
GtkAdjustment*
gtk_range_get_adjustment
(
GtkRange *
range);
void
gtk_range_set_update_policy
(
GtkRange *
range, GtkUpdateType policy);
gboolean gtk_range_get_inverted
(
GtkRange *
range);
void
gtk_range_set_inverted
(
GtkRange *
range, gboolean setting);
GtkUpdateType gtk_range_get_update_policy
(
GtkRange *
range);
GtkSpinButton
void
gtk_spin_button_configure
(
GtkSpinButton *
spin_button, GtkAdjustment *
adjustment, gdouble climb_rate, guint digits);
void
gtk_spin_button_set_increments
(
GtkSpinButton *
spin_button, gdouble step, gdouble page);
void
gtk_spin_button_set_update_policy
(
GtkSpinButton *
spin_button, GtkSpinButtonUpdatePolicy policy);
void
gtk_spin_button_set_numeric
(
GtkSpinButton *
spin_button, gboolean numeric);
void
gtk_spin_button_spin
(
GtkSpinButton *
spin_button, GtkSpinType direction, gdouble increment);
void
gtk_spin_button_set_wrap
(
GtkSpinButton *
spin_button, gboolean wrap);
void
gtk_spin_button_set_snap_to_ticks
(
GtkSpinButton *
spin_button, gboolean snap_to_ticks);
void
gtk_spin_button_update
(
GtkSpinButton *
spin_button);
void
gtk_spin_button_get_increments
(
GtkSpinButton *
spin_button, gdouble *
step, gdouble *
page);
gboolean gtk_spin_button_get_numeric
(
GtkSpinButton *
spin_button);
gboolean gtk_spin_button_get_snap_to_ticks
(
GtkSpinButton *
spin_button);
GtkSpinButtonUpdatePolicy gtk_spin_button_get_update_policy
(
GtkSpinButton *
spin_button);
gboolean gtk_spin_button_get_wrap
(
GtkSpinButton *
spin_button);
XVIII. La barre de progression▲
Parfois un programme doit faire de gros calculs, et il est utile d'avertir l'utilisateur sur l'avancement du calcul afin qu'il soit au courant et ne pense pas que le programme est bloqué. Nous allons donc étudier le widget GtkProgressBar qui sert justement à cela.
XVIII-A. Utilisation d'une GtkProgressBar▲
XVIII-A-1. Création▲
Ce widget étant comme tous les autres widgets de GTK+ sa fonction de création est très simple :
GtkWidget*
gtk_progress_bar_new
(
void
)
Voilà, nous avons maintenant notre GtkProgressBar, maintenant vous avez besoin de ne connaître que peu de fonctions pour la faire marcher.
XVIII-A-2. Modification de la progression▲
Tout d'abord nous allons voir comment connaître la position de la GtkProgressBar :
gdouble gtk_progress_bar_get_fraction
(
GtkProgressBar *
pbar);
Cette fonction renvoie un double qui sera compris entre 0.0 et 1.0, c'est-à-dire un pourcentage. Pour ce qui est du paramètre pbar, il faut utiliser la macro de conversion GTK_PROGRESS_BAR().
À l'inverse, pour fixer la position de la GtkProgressBar, la fonction est :
void
gtk_progress_bar_set_fraction
(
GtkProgressBar *
pbar, gdouble fraction);
Là aussi, le paramètre fraction doit être compris entre 0.0 et 1.0.
XVIII-A-3. Exemple▲
Notre premier exemple, très simple, sera fait d'une fenêtre (bien entendu) avec à l'intérieur une barre de progression et un bouton qui permettra de faire avancer la barre de progression de 10%. Et lorsque la barre de progression sera à 100%, nous la réinitialiserons à 0%.
XVIII-A-4. 1.4 Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnButton
(
GtkWidget *
pWidget, gpointer data);
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget *
pMainVBox;
GtkWidget *
pProgress;
GtkWidget *
pButton;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkProgressBar
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 4
);
pMainVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pMainVBox);
/* Création de la barre de progression */
pProgress =
gtk_progress_bar_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pProgress, TRUE, FALSE, 0
);
pButton =
gtk_button_new_with_label
(
"
Ajouter 10%
"
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pButton, TRUE, FALSE, 0
);
g_signal_connect_swapped
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
OnButton), pProgress);
gtk_widget_show_all
(
pWindow);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnButton
(
GtkWidget *
pWidget, gpointer data)
{
gdouble dFraction;
/* Récupération de la valeur de la barre de progression */
dFraction =
gtk_progress_bar_get_fraction
(
GTK_PROGRESS_BAR
(
pWidget));
dFraction +=
0
.1
;
if
(
dFraction >
1
.0
)
dFraction =
0
.0
;
/* Modification de la valeur de la barre de progression */
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
pWidget), dFraction);
}
Résultat :
XVIII-B. Utilisation dans une boucle for▲
XVIII-B-1. Problème▲
Si nous modifions légèrement le programme précédent pour insérer une boucle qui fera avancer automatiquement la barre de progression (par exemple une boucle de 2000 itérations) cela ne fonctionnera pas. La seule raison pour laquelle cela ne fonctionnera pas est que GTK+ ne reprend pas la main, car le programme reste dans la boucle for alors GTK+ ne peut pas mettre à jour les widgets affichés.
XVIII-B-2. Solution▲
La solution est de dire clairement à GTK+ qu'il doit remettre à jour grâce à la fonction suivante :
gboolean gtk_main_iteration
(
void
);
Cette fonction permet de faire une itération comme son nom l'indique, une est une seul donc à ce moment-là GTK+ va reprendre la main puis la rendre aussitôt, si bien qu'il pourra mettre à jour les widgets. Donc il suffit d'ajouter cette fonction après gtk_progress_bar_set_fraction pour faire fonctionner correctement notre programme.
Ce problème étant réglé, nous allons faire face à un deuxième problème, ou plutôt pseudoproblème. En général, lorsque le programme fait un gros calcul, l'application doit être « bloquée » pendant ce temps. Donc tant que le traitement n'est pas fini, il faut éviter que l'utilisateur ne puisse change des données. Prenons le cas d'un correcteur d'orthographe, disons qu'il le fasse automatiquement. Pendant qu'il vérifie l'orthographe, il serait bête que l'utilisateur puisse modifier le texte, ce qui fausserait alors toute la correction. Pourquoi cet exemple? Et bien le fait de rendre la main a GTK+ lui donne le pouvoir de traiter d'autres événements, comme un clic de souris et autres. Donc à tout moment pendant ce calcul l'utilisateur peut modifier quelque chose (ici pas grand-chose si ce n'est que recliquer sur le bouton de démarrage de la boucle), donc il faut pouvoir l'empêcher de faire une quelconque action.
Nous allons pouvoir bloquer l'utilisateur à l'aide de ces deux fonctions :
void
gtk_grab_add
(
GtkWidget *
widget);
void
gtk_grab_remove
(
GtkWidget *
widget);
Nous allons faire une description rapide de ces deux fonctions à l'aide d'un exemple. Prenons le cas ou l'utilisateur fait dans une application (de dessin par exemple) une sélection par glissement, quand il quitte la zone pour atterrir à côté voir en dehors de la fenêtre, la sélection continue, et bien c'est parce que l'application se focalise sur la fenêtre de sélection, c'est un peu ce que fait gtk_grab_add. Nous lui donnons un widget et seuls les événements de ce widget seront traités par GTK+, et cela tant que gtk_grab_remove n'a pas été invoqué. Si bien que quand l'utilisateur fait une sélection et qu'il passe au-dessus d'un autre widget, il est ignoré.
Voilà maintenant nous avons tout pour que pendant la boucle la barre de progression soit remise à jour et sans que l'utilisateur ne puisse cliquer ailleurs.
XVIII-B-3. Exemple▲
Nous réutilisons donc l'exemple précédant en modifiant la fonction du bouton qui sert maintenant à démarrer la progression de la barre qui sera effectuée dans la fonction callback.
XVIII-B-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnButton
(
GtkWidget *
pWidget, gpointer data);
int
main
(
int
argc,char
**
argv)
{
GtkWidget*
pWindow;
GtkWidget *
pMainVBox;
GtkWidget *
pProgress;
GtkWidget *
pButton;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkProgressBar
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_container_set_border_width
(
GTK_CONTAINER
(
pWindow), 4
);
pMainVBox =
gtk_vbox_new
(
TRUE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pMainVBox);
/* Création de la barre de progression */
pProgress =
gtk_progress_bar_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pProgress, TRUE, FALSE, 0
);
pButton =
gtk_button_new_from_stock
(
GTK_STOCK_REFRESH);
gtk_box_pack_start
(
GTK_BOX
(
pMainVBox), pButton, TRUE, FALSE, 0
);
g_signal_connect_swapped
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
OnButton), pProgress);
gtk_widget_show_all
(
pWindow);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnButton
(
GtkWidget *
pWidget, gpointer data)
{
gdouble dFraction;
gint i;
gint iTotal =
2000
;
/* Initialisation */
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
pWidget), 0
.0
);
/* Ici on grab sur la barre de progression pour 2 raisons : */
/* - cela évite a GTK+ de regarder tous les événements ce qui rend plus rapide */
/* l'utilisation de gtk_main_iteration() */
/* - on empêche toute action de l'utilisateur */
gtk_grab_add
(
pWidget);
for
(
i =
0
; i <
iTotal ; ++
i)
{
dFraction =
(
gdouble)i /
(
gdouble)iTotal;
/* Modification de la valeur de la barre de progression */
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
pWidget), dFraction);
/* On donne la main a GTK+ */
gtk_main_iteration
(
);
}
/* On supprime le grab sur la barre de progression */
gtk_grab_remove
(
pWidget);
}
Résultat :
XVIII-C. En savoir plus▲
XVIII-C-1. Fonctions documentées▲
void
gtk_progress_bar_set_text
(
GtkProgressBar *
pbar, const
gchar *
text);
Permet d'afficher du texte dans la barre de progression.
Entrée(s) :
- pbar : objet GtkProgressBar.
- text : texte à afficher.
Sortie : rien.
G_CONST_RETURN gchar*
gtk_progress_bar_get_text
(
GtkProgressBar *
pbar);
Permet d'obtenir le texte affiché dans la barre de progression.
Entrée(s) :
- pbar : objet GtkProgressBar.
Sortie : le texte affiché.
void
gtk_progress_bar_set_orientation
(
GtkProgressBar *
pbar, GtkProgressBarOrientation orientation);
Permet de définir le sens de progression de la GtkProgressBar.
Entrée(s) :
- pbar : objet GtkProgressBar.
-
orientation : une des valeurs suivantes
- GTK_PROGRESS_LEFT_TO_RIGHT -> de gauche à droite ;
- GTK_PROGRESS_RIGHT_TO_LEFT -> de droite à gauche ;
- GTK_PROGRESS_BOTTOM_TO_TOP -> de bas en haut ;
- GTK_PROGRESS_TOP_TO_BOTTOM -> de haut en bas.
Sortie : rien
GtkProgressBarOrientation gtk_progress_bar_get_orientation
(
GtkProgressBar *
pbar);
Permet d'obtenir le sens de progression de la GtkProgressBar.
Entrée(s) :
- pbar : objet GtkProgressBar.
Sortie : le sens de progression.
XIX. Sélection de fichier▲
Le widget GtkFileSelection est une boite de dialogue qui permet de demander à l'utilisateur le chemin d'un fichier particulier, à travers une liste de répertoire et de fichiers.
XIX-A. Créer une gtk_file_selection et l'utiliser▲
Nous allons ici créer une gtk_file_selection, et apprendre comment récupérer le chemin entré par l'utilisateur.
XIX-A-1. 1.1 Créer le widget▲
On crée tout d'abord un pointeur vers la structure GtkWidget.
GtkWidget*
file_selection;
Maintenant, on va instancier ce pointeur grâce à la fonction
GtkWidget*
gtk_file_selection_new
(
const
gchar*
title)
Cette fonction renvoie l'adresse d'une structure GtkFileSelection. L'argument « const gchar *title » est le titre de votre boite de dialogue : vous pouvez ainsi l'appeler suivant vos besoins « ouvrir… », « sélectionner un fichier… », etc.
XIX-A-2. Affichage▲
Tout simplement :
gtk_window_show
(
file_selection);
Qui permet d'afficher la fenêtre et en même temps ce qu'elle contient (donc le label).
XIX-A-3. 1.3 Récupérer le chemin▲
Notre but est de récupérer le chemin spécifié par l'utilisateur lorsque celui-ci appuie sur le bouton OK.
On va pour cela tout d'abord utiliser le callback suivant, qui lorsque le bouton sera appuyé, appellera la fonction recuperer_chemin(GtkWidget *bouton, GtkWidget *file_selection) :
g_signal_connect
(
GTK_FILE_SELECTION
(
file_selection)->
ok_button, "
clicked
"
, G_CALLBACK
(
recuperer_chemin), file_selection );
On voit ici que le bouton OK est une donnée membre de la structure GtkFileSelection : ok_button. Ce callback va fournir à la fonction recuperer_chemin un pointeur file_selection pour lui permettre de récupérer le chemin. Voilà la fonction qui permet d'obtenir le chemin du fichier ou du répertoire sélectionné à partir de la gtk_file_selection :
G_CONST_RETURN gchar*
gtk_file_selection_get_filename
(
GtkFileSelection *
filesel);
Voyons maintenant comment nous pouvons l'utiliser dans notre fonction :
void
recuperer_chemin
(
GtkWidget *
bouton, GtkWidget *
file_selection)
{
gchar *
chemin;
chemin =
gtk_file_selection_get_filename
(
GTK_FILE_SELECTION
(
file_selection) );
}
Enfin, il est nécessaire de détruire la boite de dialogue lorsque l'utilisateur clique sur le bouton cancel, et lorsque le chemin a été récupéré. Pour ce faire, faisons les deux callbacks suivants après le callback précédent :
g_signal_connect_swapped
(
GTK_FILE_SELECTION
(
file_selection)->
ok_button, "
clicked
"
, G_CALLBACK
(
gtk_widget_destroy), file_selection);
g_signal_connect_swapped
(
GTK_FILE_SELECTION
(
file_selection)->
cancel_button, "
clicked
"
, G_CALLBACK
(
gtk_widget_destroy), file_selection);
Le fait d'appeler g_signal_connect_swapped va permettre de ne pas transmettre l'argument inhérent au signal clicked sur les boutons à gtk_widget_destroy, mais seulement l'argument file_selection. Notez que l'appel des fonctions callbacks se fait dans l'ordre de leur définition, ainsi le callback entre le ok_button et la fonction gtk_widget_destroy se fera après l'appel de la fonction recuperer_chemin. Lorsque la fenêtre sera détruite, le chemin sera récupéré.
XIX-A-4. Programme d'exemple▲
#include <gtk/gtk.h>
void
quitter
(
GtkWidget *
widget); void
creer_file_selection
(
);
void
recuperer_chemin
(
GtkWidget *
bouton, GtkWidget *
file_selection);
int
main
(
int
argc,char
*
argv[])
{
GtkWidget *
win;
GtkWidget *
bouton_explorer;
gtk_init
(&
argc,&
argv);
win =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
win),"
GtkFileSelection
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
win),320
,200
);
// On crée un bouton explorer
bouton_explorer=
gtk_button_new_with_mnemonic
(
"
_Explorer...
"
);
// on met bouton_explorer dans win
gtk_container_add
(
GTK_CONTAINER
(
win),bouton_explorer);
g_signal_connect
(
G_OBJECT
(
win),"
destroy
"
,G_CALLBACK
(
quitter), NULL
);
g_signal_connect
(
G_OBJECT
(
bouton_explorer), "
clicked
"
, G_CALLBACK
(
creer_file_selection), NULL
);
// affichage de win et de ce qu'il contient
gtk_widget_show_all
(
win);
gtk_main
(
);
return
0
;
}
void
quitter
(
GtkWidget*
widget)
{
// destruction de win et de tout ce qu'il contient
gtk_widget_destroy
(
widget);
gtk_main_quit
(
);
}
void
creer_file_selection
(
)
{
GtkWidget *
selection;
selection =
gtk_file_selection_new
(
g_locale_to_utf8
(
"
Sélectionnez un fichier
"
, -
1
, NULL
, NULL
, NULL
) );
gtk_widget_show
(
selection);
//On interdit l'utilisation des autres fenêtres.
gtk_window_set_modal
(
GTK_WINDOW
(
selection), TRUE);
g_signal_connect
(
G_OBJECT
(
GTK_FILE_SELECTION
(
selection)->
ok_button), "
clicked
"
, G_CALLBACK
(
recuperer_chemin), selection );
g_signal_connect_swapped
(
G_OBJECT
(
GTK_FILE_SELECTION
(
selection)->
cancel_button), "
clicked
"
, G_CALLBACK
(
gtk_widget_destroy), selection);
}
void
recuperer_chemin
(
GtkWidget *
bouton, GtkWidget *
file_selection)
{
const
gchar*
chemin;
GtkWidget *
dialog;
chemin =
gtk_file_selection_get_filename
(
GTK_FILE_SELECTION (
file_selection) );
dialog =
gtk_message_dialog_new
(
GTK_WINDOW
(
file_selection),
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Vous avez choisi :
\n
%s
"
, chemin);
gtk_dialog_run
(
GTK_DIALOG
(
dialog));
gtk_widget_destroy
(
dialog);
gtk_widget_destroy
(
file_selection);
}
Résultat :
XIX-B. En savoir plus▲
XIX-B-1. Fonctions documentées▲
void
gtk_file_selection_set_filename
(
GtkFileSelection *
filesel,const
gchar *
filename);
Permet de définir le chemin par défaut.
Entrée(s) :
- filesel : la GtkFileSelection.
- filename : le chemin.
Sortie : rien.
void
gtk_file_selection_hide_fileop_buttons
(
GtkFileSelection *
filesel);
Permet de cacher certains boutons de la boite de dialogue(nouveau dossier, effacer le fichier, renommer le fichier
Entrée(s) :
- filesel : la GtkFileSelection.
Sortie : rien
void
gtk_file_selection_show_fileop_buttons
(
GtkFileSelection *
filesel);
Permet d'afficher certains boutons de la boite de dialogue(nouveau dossier, effacer le fichier, renommer le fichier).
Entrée(s) :
- filesel : la GtkFileSelection.
Sortie : rien.
void
gtk_file_selection_set_select_multiple
(
GtkFileSelection *
filesel,gboolean select_multiple);
On définit si l'on peut selectionner plusieurs fichiers.
Entrée(s) :
- filesel : objet GtkFileSelection.
- select_multiple : TRUE pour une selection multiple, FALSE (par défaut) sinon.
Sortie : rien.
gchar**
gtk_file_selection_get_selections
(
GtkFileSelection *
filesel);
L'équivalent de gtk_file_selection_get_filename,mais pour des sélections multiples.
Entrée(s) :
- filesel : objet GtkFileSelection.
Sortie : un tableau contenant les différents chemins.
XX. Les fenêtres avec barres de défilement▲
Nous allons cette fois voir un widget qui permet d'ajouter des barres de défilement au widget qui sera son enfant. Il s'agit d'un widget container qui s'appelle GtkScrolledWindow.
XX-A. Création et utilisation d'une GtkScrolledWindow▲
XX-A-1. Création▲
Comme vous pouvez vous y attendre, la fonction de création et comme toutes les autres, c'est-à-dire prévisible.
GtkWidget*
gtk_scrolled_window_new
(
GtkAdjustment *
hadjustment, GtkAdjustment *
vadjustment);
Les paramètres hadjustment et vadjustment permettent de définir les propriétés des barres de défilement. L'objet GtkAdjustment permet dans notre cas, de définir (entre autres) la valeur minimale que peut prendre la barre de défilement, le pas de celle-ci.
Mais à moins de connaître exactement tous ces paramètres, il vaut mieux laisser faire Gtk, et mettre hadjustment et vadjustment à NULL.
XX-A-2. Ajout du widget enfant▲
Pour cela, il y a deux cas différents. Si par exemple le widget enfant a la capacité d'avoir ses propres barres de défilement, il suffit d'utiliser la fonction gtk_container_add.
Par contre, dans le cas où le widget ne possède pas cette capacité, il faudra utiliser cette fonction :
void
gtk_scrolled_window_add_with_viewport
(
GtkScrolledWindow *
scrolled_window, GtkWidget *
child);
Avec cette fonction, Gtk va créer ce qu'il s'appelle un viewport (qui peut avec des barres de défilement) et va insérer l'enfant dans ce viewport.
Seuls les widgets GtkTreeView, GtkTextView, et GtkLayout ont la possibilité d'avoir des barres de débilement. Pour les autres widgets (comme les GtkHBox, GtkVBox…) il faudra utiliser la deuxième fonction.
XX-A-3. Affichage des barres de défilement▲
Les barres de défilement s'affichent automatiquement (que ce soit la barre horizontale ou verticale). Il se peut que, par exemple, vous n'ayez besoin que de la barre verticale. Dans ce cas vous ne voulez sûrement pas avoir de barre de défilement horizontale. La solution à votre problème est cette fonction :
void
gtk_scrolled_window_set_policy
(
GtkScrolledWindow *
scrolled_window, GtkPolicyType hscroll_policy, GtkPolicyType vscroll_policy);
Les paramètres hscroll_policy et vscroll_policy peuvent prendre trois paramètres :
- GTK_POLICY_ALWAYS : la barre de défilement est toujours affichée ;
- GTK_POLICY_AUTOMATIC : la barre de défilement n'est affichée que si elle est utile ;
- GTK_POLICY_NEVER : la barre de défilement n'est jamais affichée.
Au contraire, pour savoir si elles sont affichées ou pas, il y a la fonction :
void
gtk_scrolled_window_get_policy
(
GtkScrolledWindow *
scrolled_window, GtkPolicyType *
hscroll_policy, GtkPolicyType *
vscroll_policy);
XX-A-4. 1.4 Construction du programme exemple▲
Notre exemple est très simple. Il consiste uniquement à afficher 10 labels les uns au-dessus des autres dans une fenêtre qui n'excédera pas une taille de 320x200. Voyons à quoi ressemble notre fenêtre si elle n'utilise pas les barres de défilement.
Et voilà le résultat, la fenêtre ne respecte pas la condition TAILLE = 320x200. Il faut utiliser le widget GtkScrolledWindow.
Après avoir créé notre fenêtre principale, il faut créer notre widget et l'insérer dans la fenêtre :
scrollbar =
gtk_scrolled_window_new
(
NULL
, NULL
);
gtk_container_add
(
GTK_CONTAINER
(
window),scrollbar);
Ensuite les labels seront contenus dans une GtkVBox qu'il faut insérer ainsi dans notre GtkScrolledWindow :
gtk_scrolled_window_add_with_viewport
(
GTK_SCROLLED_WINDOW
(
scrollbar), box);
Puisque nous n'avons pas besoin de la barre de défilement horizontale, on la supprime :
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
scrollbar), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
Et voilà notre toute nouvelle fenêtre est créée.
XX-A-5. 1.5 Programme exemple▲
#include <gtk/gtk.h>
#include <stdio.h>
int
main
(
int
argc, char
*
argv[])
{
GtkWidget*
window;
GtkWidget*
box;
GtkWidget *
scrollbar;
int
i;
gtk_init
(&
argc, &
argv);
window =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
window), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
window), "
GtkScrolledWindow
"
);
g_signal_connect
(
G_OBJECT
(
window),"
destroy
"
,G_CALLBACK
(
gtk_main_quit),0
);
scrollbar =
gtk_scrolled_window_new
(
NULL
, NULL
);
gtk_container_add
(
GTK_CONTAINER
(
window),scrollbar);
box=
gtk_vbox_new
(
FALSE,5
);
gtk_scrolled_window_add_with_viewport
(
GTK_SCROLLED_WINDOW
(
scrollbar), box);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
scrollbar), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
for
(
i =
1
; i <=
10
; ++
i)
{
GtkWidget *
label;
char
texte[10
];
sprintf
(
texte, "
Label %d
"
, i);
label =
gtk_label_new
(
texte);
gtk_box_pack_start
(
GTK_BOX
(
box), label, FALSE, FALSE, 5
);
}
gtk_widget_show_all
(
window);
gtk_main
(
);
return
0
;
}
Résultat :
XX-B. En savoir plus▲
XX-B-1. Signaux▲
Prototypes fonctions callback :
-
move-focus-out
Sélectionnezvoid
user_function
(
GtkScrolledWindow*
scrolledwindow, GtkDirectionType arg1, gpointer user_data); - scroll-child
void
user_function
(
GtkScrolledWindow *
scrolledwindow, GtkScrollType arg1, gboolean arg2, gpointer user_data);
XX-B-2. Fonctions documentées▲
GtkAdjustment*
gtk_scrolled_window_get_hadjustment
(
GtkScrolledWindow *
scrolled);
Pour obtenir les paramètres de la barre de défilement horizontale.
Entrée(s) :
- scrolled : la fenêtre.
Sortie : un pointeur sur la structure GtkAdjustment contenant les paramètres.
GtkAdjustment*
gtk_scrolled_window_get_vadjustment
(
GtkScrolledWindow *
scrolled);
Pour obtenir les paramètres de la barre de défilement verticale.
Entrée(s) :
- scrolled : la fenêtre.
Sortie : un pointeur sur la structure GtkAdjustment contenant les paramètres.
void
gtk_scrolled_window_set_hadjustment
(
GtkScrolledWindow *
scrolled, GtkAdjustment *
hadjustment);
Définit les paramètres de la barre de défilement horizontale.
Entrée(s) :
- scrolled : la fenêtre.
- hadjustment : structure contenant les paramètres à appliquer.
Sortie : rien.
void
gtk_scrolled_window_set_vadjustment
(
GtkScrolledWindow *
scrolled, GtkAdjustment *
vadjustment);
Définit les paramètres de la barre de défilement verticale.
Entrée(s) :
- scrolled : la fenêtre.
- vadjustment : structure contenant les paramètres à appliquer.
Sortie : rien.
void
gtk_scrolled_window_set_shadow_type
(
GtkScrolledWindow *
scrolled, GtkShadowType type);
Modifie l'aspect du bord du widget enfant à la GtkScrolledWindow.
Entrée(s) :
- scrolled : la fenêtre.
-
type : une valeur parmi
- GTK_SHADOW_NONE ;
- GTK_SHADOW_IN ;
- GTK_SHADOW_OUT ;
- GTK_SHADOW_ETCHED_IN ;
- GTK_SHADOW_ETCHED_OUT.
Sortie : rien.
GtkShadowType gtk_scrolled_window_get_shadow_type
(
GtkScrolledWindow *
scrolled);
Pour connaître l'aspect du bord du widget enfant.
Entrée(s) :
- scrolled : la fenêtre.
Sortie : type de l'aspect.
void
gtk_scrolled_window_set_placement
(
GtkScrolledWindow *
scrolled, GtkCornerType window_placement);
Définit la position du widget enfant par rapport aux barres de défilement.
Entrée(s) :
- scrolled : la fenêtre.
-
window_placement : la position du widget, peut-être
- GTK_CORNER_TOP_LEFT -> en dessus à gauche ;
- GTK_CORNER_BOTTOM_LEFT -> en dessous à gauche ;
- GTK_CORNER_TOP_RIGHT -> en dessus à droite ;
- GTK_CORNER_BOTTOM_RIGHT -> en dessous à droite.
Sortie : rien.
GtkCornerType gtk_scrolled_window_get_placement
(
GtkScrolledWindow *
scrolled);
Pour obtenir la position du widget enfant par rapport aux barres de défilement.
Entrée(s) :
- scrolled : la fenêtre.
Sortie : la position du widget.
XXI. Les zones de texte▲
Nous avons appris à saisir une ligne tapée par l'utilisateur grâce à GtkEntry, mais comment fait-on pour saisir plusieurs lignes (comme le font les traitements de texte, etc.). Et bien nous utilisons non pas un, mais trois widgets !
GtkTextBuffer : Ce widget non graphique sert à stocker les données. C'est tout simplement un buffer !
GtkTextView : Ce widget sert à afficher le contenu d'un GtkTextBuffer. Il s'occupe de tout ce qui est graphique : il gère les événements de l'utilisateur, les insertions de caractères, etc.
GtkTextIter : Ce widget non graphique désigne une position dans GtkTextBuffer. Il permet de manipuler GtkTextBuffer.
XXI-A. Créer une application saisissant un paragraphe▲
XXI-A-1. Afficher un GtkTextView▲
On va maintenant initialiser un pointeur de type GtkWidget* qui pointera vers la structure du GtkTextView :
GtkWidget*
text_view=
gtk_text_view_new
(
);
Là, nous venons de créer un GtkTextView, mais également un GtkTextBuffer. Si nous voulons donner notre propre buffer, nous utiliserons la fonction GtkWidget* gtk_text_view_new_with_buffer(GtkTextBuffer* buffer) qui reçoit en argument l'adresse de notre buffer.
Il faut maintenant insérer text_view dans la box.
gtk_box_pack_start
(
GTK_BOX
(
box),text_view,TRUE,TRUE,0
);
C bon ! On peut commencer à compiler pour voir le résultat et même commencer à saisir du texte dedans (mais ça ne sert strictement à rien :-).
XXI-A-2. Accéder au contenu de GtkTextBuffer▲
Tout d'abord, on va créer un bouton qui dès qu'il sera cliqué par l'utilisateur, on saisira le contenu du buffer :
button=
gtk_button_new_with_label
(
"
Valider
"
);
gtk_box_pack_start
(
GTK_BOX
(
box),button,false
,false
,0
);
g_signal_connect
(
G_OBJECT
(
button),"
clicked
"
,G_CALLBACK
(
saisie),text_view);
Pendant la connexion du signal, on envoie text_view pour pouvoir travailler dessus dans la fonction callback :
void
saisie
(
GtkButton *
button, gpointer user_data)
{
}
Ce qui suit est à insérer dans la fonction.
Comme on n'a pas donné « notre » GtkTextBuffer pendant la création de text_view, GTK+ a donné un buffer par défaut. Pour récupérer l'adresse de ce buffer, on utilise la fonction
GtkTextBuffer*
gtk_text_view_get_buffer
(
GtkTextView*
text_view)
On va bien sûr recevoir la valeur renvoyée par la fonction dans un pointeur de type GtkTextBuffer* et non pas GtkWidget* :
text_buffer=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
user_data));
Enregistrer la macro de conversion au passage…
Maintenant, reste plus qu'à extraire les données contenues dans text_buffer et les mettre dans un gchar* par exemple. On utilise la fonction
gchar*
gtk_text_buffer_get_text
(
GtkTextBuffer *
buffer, const
GtkTextIter *
start, const
GtkTextIter *
end, gboolean include_hidden_chars)
Où là ! C'est quoi tous ces paramètres ! On va les traiter un par un :
- buffer : pas de commentaire
- start : la position de début de la chaîne de caractère
- end : la position de fin de la chaîne de caractère
- include_hidden_chars : on verra plus tard :-) (mettre false)
- valeur retournée : une chaîne de caractère de type C et allouée dans le tas
Mais à quoi peuvent bien servir le deuxième et le troisième paramètre ? Et bien imaginez que vous ne vouliez qu'une partie du buffer, et bien ces deux paramètres indiquent la position de début et de fin de la chaîne de caractère dans le buffer. On appelle cela une sous-chaîne de caractère.
Mais comment ça s'initialise les GtkTextIter ?
On ne va pas déclarer des pointeurs comme on a l'habitude de le faire, mais des variables directo. Nous voulons recevoir tout le buffer. Les itérateurs doivent être les itérateurs de début et de fin de text_buffer. Pour ce faire, nous utiliserons les deux fonctions :
void
gtk_text_buffer_get_start_iter
(
GtkTextBuffer *
buffer, GtkTextIter *
iter)
void
gtk_text_buffer_get_end_iter
(
GtkTextBuffer *
buffer, GtkTextIter *
iter)
On va donc initialiser nos deux itérateurs comme cela :
gtk_text_buffer_get_start_iter
(
text_buffer,&
start);
gtk_text_buffer_get_end_iter
(
text_buffer,&
end);
À noter que nous n'avons pas besoin de la macro de conversion GTK_TEXT_BUFFER() pour text_buffer,car c'est déjà un pointeur de type GtkTextBuffer* et ne pas oublier le & avant start et end car ce ne sont pas des pointeurs. Et la fonction reçoit leur adresse.
Maintenant, on va utiliser la fonction gtk_text_buffer_get_text :
buf=
gtk_text_buffer_get_text
(
text_buffer,&
start,&
end,false
);
Et voilà ! Nous avons le contenu de text_buffer copié dans buf. On peut faire ce qu'on veut avec maintenant : le copier dans un fichier, l'afficher dans un autre widget, etc.
Il ne faut surtout pas oublier d'utiliser la fonction g_free() qui est la version GTK+ de la fonction free du C pour libérer la mémoire allouée dans le tas par buf :
g_free
(
buf);
XXI-A-3. Programme exemple▲
#include <gtk\gtk.h>
gboolean fin
(
GtkWidget *
widget, GdkEvent *
event, gpointer user_data);
void
saisie
(
GtkButton *
button, GtkWidget *
view);
int
main
(
int
argc, char
*
argv[])
{
GtkWidget*
window;
GtkWidget*
box;
GtkWidget*
text_view;
GtkWidget*
button;
gtk_init
(&
argc, &
argv);
window =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
window), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
window), "
XIII. Les zones de texte.
"
);
g_signal_connect
(
G_OBJECT
(
window),"
destroy
"
,G_CALLBACK
(
gtk_main_quit),0
);
box=
gtk_vbox_new
(
FALSE,5
);
gtk_container_add
(
GTK_CONTAINER
(
window),box);
text_view=
gtk_text_view_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
box),text_view,TRUE,TRUE,0
);
button=
gtk_button_new_with_label
(
"
Afficher
"
);
gtk_box_pack_start
(
GTK_BOX
(
box),button,FALSE,FALSE,0
);
g_signal_connect
(
G_OBJECT
(
button),"
clicked
"
,G_CALLBACK
(
saisie),text_view);
gtk_widget_show_all
(
window);
gtk_main
(
);
return
0
;
}
gboolean fin
(
GtkWidget *
widget, GdkEvent *
event, gpointer user_data)
{
gtk_widget_destroy
(
widget);
gtk_main_quit
(
);
return
0
;
}
void
saisie
(
GtkButton *
button, GtkWidget *
view)
{
GtkWidget *
dialog;
GtkTextBuffer*
text_buffer=
0
;
GtkTextIter start;
GtkTextIter end;
gchar*
buf=
0
;
//On récupère le buffer
text_buffer=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
view));
//On récupère l'origine du buffer
gtk_text_buffer_get_start_iter
(
text_buffer,&
start);
//On récupère la fin du buffer
gtk_text_buffer_get_end_iter
(
text_buffer,&
end);
//On copie le contenu du buffer dans une variable
buf=
gtk_text_buffer_get_text
(
text_buffer,&
start, &
end,TRUE);
//On affiche le texte dans une boite de dialogue.
dialog =
gtk_message_dialog_new
(
NULL
,
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"
Votre texte :
\n
%s
"
, buf);
gtk_dialog_run
(
GTK_DIALOG
(
dialog));
gtk_widget_destroy
(
dialog);
//On libere la memoire
g_free
(
buf);
}
Résultat :
XXI-B. Affichage du contenu d'un fichier▲
Maintenant, nous allons utiliser ce que nous avons vu dans les deux précédents chapitres afin de créer une application ouvrant un fichier et affichant son contenu.
XXI-B-1. Construction de l'application▲
Nous avons déjà vu la quasi-totalité des fonctions que nous allons utiliser pour ce programme, cela va donc aller assez vite. Nous allons étudier uniquement la partie du code qui a pour fonction de lire le fichier et d'afficher le texte.
Dans un premier temps, nous allons récupérer le buffer de notre GtkTextView.
buffer =
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
text_view));
Ensuite on récupère le chemin du fichier et on l'ouvre en mode texte :
chemin =
gtk_file_selection_get_filename
(
GTK_FILE_SELECTION
(
file_selection));
fichier =
fopen
(
chemin,"
rt
"
);
Si le fichier ne s'est pas ouvert correctement, on affiche bien sûr un message d'erreur.
On vide ensuite le contenu du buffer avec cette fonction.
void
gtk_text_buffer_delete
(
GtkTextBuffer *
buffer, GtkTextIter *
start, GtkTextIter *
end);
Il faut bien sûr récupérer auparavant les valeurs start et end comme pour le premier exemple.
gtk_text_buffer_delete
(
buffer, &
start, &
end);
Ensuite, le procédé consiste à lire les lignes du fichier une par une et à les ajouter au buffer avec la fonction :
void
gtk_text_buffer_insert
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
gchar *
text, gint len);
Le paramètre iter est la position du buffer à partir de laquelle le texte text va être ajouté. Il faut donc avant chaque insertion récupérer la position finale du buffer pour que le texte se place correctement. Voici la boucle qui nous permet de créer notre buffer.
while
(
fgets
(
lecture, 1024
, fichier))
{
gtk_text_buffer_get_end_iter
(
buffer,&
end);
gtk_text_buffer_insert
(
buffer, &
end, g_locale_to_utf8
(
lecture, -
1
, NULL
, NULL
, NULL
), -
1
);
}
Et voilà le code source est complet.
XXI-B-2. 2.2 Programme exemple▲
#include <gtk/gtk.h>
#include <stdio.h>
static
GtkWidget *
text_view;
void
saisie
(
GtkButton *
button);
void
ouvrir_fichier
(
GtkWidget *
bouton, GtkWidget *
file_selection);
int
main
(
int
argc, char
*
argv[])
{
GtkWidget*
window;
GtkWidget*
box;
GtkWidget*
button;
GtkWidget *
scrollbar;
gtk_init
(&
argc, &
argv);
window =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
window), 480
, 480
);
gtk_window_set_title
(
GTK_WINDOW
(
window), "
XIII. Les zones de texte.
"
);
g_signal_connect
(
G_OBJECT
(
window),"
destroy
"
,G_CALLBACK
(
gtk_main_quit),0
);
box=
gtk_vbox_new
(
FALSE,5
);
gtk_container_add
(
GTK_CONTAINER
(
window),box);
scrollbar =
gtk_scrolled_window_new
(
NULL
, NULL
);
gtk_box_pack_start
(
GTK_BOX
(
box), scrollbar, TRUE, TRUE, 5
);
text_view=
gtk_text_view_new
(
);
gtk_container_add
(
GTK_CONTAINER
(
scrollbar),text_view);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
scrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
button=
gtk_button_new_with_label
(
g_locale_to_utf8
(
"
Sélectionnez un fichier
"
, -
1
, NULL
, NULL
, NULL
));
gtk_box_pack_start
(
GTK_BOX
(
box),button,FALSE,FALSE,0
);
g_signal_connect
(
G_OBJECT
(
button),"
clicked
"
,G_CALLBACK
(
saisie),NULL
);
gtk_widget_show_all
(
window);
gtk_main
(
);
return
0
;
}
void
saisie
(
GtkButton *
button)
{
GtkWidget *
selection;
selection =
gtk_file_selection_new
(
g_locale_to_utf8
(
"
Sélectionnez un fichier
"
, -
1
, NULL
, NULL
, NULL
) );
gtk_widget_show
(
selection);
g_signal_connect
(
G_OBJECT
(
GTK_FILE_SELECTION
(
selection)->
ok_button), "
clicked
"
, G_CALLBACK
(
ouvrir_fichier), selection );
g_signal_connect_swapped
(
G_OBJECT
(
GTK_FILE_SELECTION
(
selection)->
cancel_button), "
clicked
"
, G_CALLBACK
(
gtk_widget_destroy), selection);
}
void
ouvrir_fichier
(
GtkWidget *
bouton, GtkWidget *
file_selection)
{
GtkTextBuffer *
buffer;
GtkTextIter start;
GtkTextIter end;
FILE *
fichier;
const
gchar *
chemin;
gchar lecture[1024
];
buffer =
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
text_view));
chemin =
gtk_file_selection_get_filename
(
GTK_FILE_SELECTION (
file_selection));
fichier =
fopen
(
chemin,"
rt
"
);
if
(
fichier ==
NULL
)
{
GtkWidget *
dialog;
dialog =
gtk_message_dialog_new
(
GTK_WINDOW
(
file_selection), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "
Impossible d'ouvrir le fichier :
\n
%s
"
, g_locale_to_utf8
(
chemin, -
1
, NULL
, NULL
, NULL
));
gtk_dialog_run
(
GTK_DIALOG
(
dialog));
gtk_widget_destroy
(
dialog);
gtk_widget_destroy
(
file_selection);
return
;
}
gtk_widget_destroy
(
file_selection);
gtk_text_buffer_get_start_iter
(
buffer,&
start);
gtk_text_buffer_get_end_iter
(
buffer,&
end);
gtk_text_buffer_delete
(
buffer, &
start, &
end);
while
(
fgets
(
lecture, 1024
, fichier))
{
gtk_text_buffer_get_end_iter
(
buffer,&
end);
gtk_text_buffer_insert
(
buffer, &
end, g_locale_to_utf8
(
lecture, -
1
, NULL
, NULL
, NULL
), -
1
);
}
fclose
(
fichier);
}
Résultat :
XXI-C. En savoir plus▲
XXI-C-1. Les signaux▲
Prototypes fonctions callback :
GtkTextView
-
copy-clipboard
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gpointer user_data); -
cut-clipboard
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gpointer user_data); -
delete-from-cursor
Sélectionnezvoid
user_function
(
GtkTextView*
textview, GtkDeleteType arg1, gint arg2, gpointer user_data); -
insert-at-cursor
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gchar*
arg1, gpointer user_data); -
move-cursor
Sélectionnezvoid
user_function
(
GtkTextView*
textview, GtkMovementStep arg1, gint arg2, gboolean arg3, gpointer user_data); -
move-focus
Sélectionnezvoid
user_function
(
GtkTextView*
textview, GtkDirectionType arg1, gpointer user_data); -
page-horizontally
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gint arg1, gboolean arg2, gpointer user_data); -
paste-clipboard
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gpointer user_data); -
populate-popup
Sélectionnezvoid
user_function
(
GtkTextView*
textview, GtkMenu*
arg1, gpointer user_data); -
set-anchor
Sélectionnezvoid
user_function
(
GtkTextView*
textview, gpointer user_data); -
set-scroll-adjustments
Sélectionnezvoid
user_function
(
GtkTextView*
textview, GtkAdjustment*
arg1, GtkAdjustment*
arg2, gpointer user_data); - toggle-overwrite
void
user_function
(
GtkTextView *
textview, gpointer user_data);
GtkTextBuffer :
-
apply-tag
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTextTag*
arg1, GtkTypeTextIter arg2, GtkTypeTextIter arg3, gpointer user_data); -
begin-user-action
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, gpointer user_data); -
changed
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, gpointer user_data); -
delete-range
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTypeTextIter arg1, GtkTypeTextIter arg2, gpointer user_data); -
end-user-action
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, gpointer user_data); -
insert-child-anchor
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTypeTextIter arg1, GtkTextChildAnchor*
arg2, gpointer user_data); -
insert-pixbuf
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTypeTextIter arg1, GdkPixbuf*
arg2, gpointer user_data); -
insert-text
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTypeTextIter arg1, gchar*
arg2, gint arg3, gpointer user_data); -
mark-deleted
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTextMark*
arg1, gpointer user_data); -
mark-set
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, GtkTypeTextIter arg1, GtkTextMark*
arg2, gpointer user_data); -
modified-changed
Sélectionnezvoid
user_function
(
GtkTextBuffer*
textbuffer, gpointer user_data); - remove-tag
void
user_function
(
GtkTextBuffer *
textbuffer, GtkTextTag *
arg1, GtkTypeTextIter arg2, GtkTypeTextIter arg3, gpointer user_data);
XXI-C-2. Fonctions non documentées▲
GtkTextView :
GtkWidget*
gtk_text_view_new_with_buffer
(
GtkTextBuffer *
buffer);
void
gtk_text_view_set_buffer
(
GtkTextView *
text_view, GtkTextBuffer *
buffer);
GtkTextBuffer*
gtk_text_view_get_buffer
(
GtkTextView *
text_view);
void
gtk_text_view_scroll_to_mark
(
GtkTextView *
text_view, GtkTextMark *
mark, gdouble within_margin, gboolean use_align, gdouble xalign, gdouble yalign);
gboolean gtk_text_view_scroll_to_iter
(
GtkTextView *
text_view, GtkTextIter *
iter, gdouble within_margin, gboolean use_align, gdouble xalign, gdouble yalign);
void
gtk_text_view_scroll_mark_onscreen
(
GtkTextView *
text_view, GtkTextMark *
mark);
gboolean gtk_text_view_move_mark_onscreen
(
GtkTextView *
text_view, GtkTextMark *
mark);
gboolean gtk_text_view_place_cursor_onscreen
(
GtkTextView *
text_view);
void
gtk_text_view_get_visible_rect
(
GtkTextView *
text_view, GdkRectangle *
visible_rect);
void
gtk_text_view_get_iter_location
(
GtkTextView *
text_view, const
GtkTextIter *
iter, GdkRectangle *
location);
void
gtk_text_view_get_line_at_y
(
GtkTextView *
text_view, GtkTextIter *
target_iter, gint y, gint *
line_top);
void
gtk_text_view_get_line_yrange
(
GtkTextView *
text_view, const
GtkTextIter *
iter, gint *
y, gint *
height);
void
gtk_text_view_get_iter_at_location
(
GtkTextView *
text_view, GtkTextIter *
iter, gint x, gint y);
void
gtk_text_view_buffer_to_window_coords
(
GtkTextView *
text_view, GtkTextWindowType win, gint buffer_x, gint buffer_y, gint *
window_x, gint *
window_y);
void
gtk_text_view_window_to_buffer_coords
(
GtkTextView *
text_view, GtkTextWindowType win, gint window_x, gint window_y, gint *
buffer_x, gint *
buffer_y);
GdkWindow*
gtk_text_view_get_window
(
GtkTextView *
text_view, GtkTextWindowType win);
GtkTextWindowType gtk_text_view_get_window_type
(
GtkTextView *
text_view, GdkWindow *
window);
void
gtk_text_view_set_border_window_size
(
GtkTextView *
text_view, GtkTextWindowType type, gint size);
gint gtk_text_view_get_border_window_size
(
GtkTextView *
text_view, GtkTextWindowType type);
gboolean gtk_text_view_forward_display_line
(
GtkTextView *
text_view, GtkTextIter *
iter);
gboolean gtk_text_view_backward_display_line
(
GtkTextView *
text_view, GtkTextIter *
iter);
gboolean gtk_text_view_forward_display_line_end
(
GtkTextView *
text_view, GtkTextIter *
iter);
gboolean gtk_text_view_backward_display_line_start
(
GtkTextView *
text_view, GtkTextIter *
iter);
gboolean gtk_text_view_starts_display_line
(
GtkTextView *
text_view, const
GtkTextIter *
iter);
gboolean gtk_text_view_move_visually
(
GtkTextView *
text_view, GtkTextIter *
iter, gint count);
void
gtk_text_view_add_child_at_anchor
(
GtkTextView *
text_view, GtkWidget *
child, GtkTextChildAnchor *
anchor);
GtkTextChildAnchor*
gtk_text_child_anchor_new
(
void
);
GList*
gtk_text_child_anchor_get_widgets
(
GtkTextChildAnchor *
anchor);
gboolean gtk_text_child_anchor_get_deleted
(
GtkTextChildAnchor *
anchor);
void
gtk_text_view_add_child_in_window
(
GtkTextView *
text_view, GtkWidget *
child, GtkTextWindowType which_window, gint xpos, gint ypos);
void
gtk_text_view_move_child
(
GtkTextView *
text_view, GtkWidget *
child, gint xpos, gint ypos);
void
gtk_text_view_set_wrap_mode
(
GtkTextView *
text_view, GtkWrapMode wrap_mode);
GtkWrapMode gtk_text_view_get_wrap_mode
(
GtkTextView *
text_view);
void
gtk_text_view_set_editable
(
GtkTextView *
text_view, gboolean setting);
gboolean gtk_text_view_get_editable
(
GtkTextView *
text_view);
void
gtk_text_view_set_cursor_visible
(
GtkTextView *
text_view, gboolean setting);
gboolean gtk_text_view_get_cursor_visible
(
GtkTextView *
text_view);
void
gtk_text_view_set_pixels_above_lines
(
GtkTextView *
text_view, gint pixels_above_lines);
gint gtk_text_view_get_pixels_above_lines
(
GtkTextView *
text_view);
void
gtk_text_view_set_pixels_below_lines
(
GtkTextView *
text_view, gint pixels_below_lines);
gint gtk_text_view_get_pixels_below_lines
(
GtkTextView *
text_view);
void
gtk_text_view_set_pixels_inside_wrap
(
GtkTextView *
text_view, gint pixels_inside_wrap);
gint gtk_text_view_get_pixels_inside_wrap
(
GtkTextView *
text_view);
void
gtk_text_view_set_justification
(
GtkTextView *
text_view, GtkJustification justification);
GtkJustification gtk_text_view_get_justification
(
GtkTextView *
text_view);
void
gtk_text_view_set_left_margin
(
GtkTextView *
text_view, gint left_margin);
gint gtk_text_view_get_left_margin
(
GtkTextView *
text_view);
void
gtk_text_view_set_right_margin
(
GtkTextView *
text_view, gint right_margin);
gint gtk_text_view_get_right_margin
(
GtkTextView *
text_view);
void
gtk_text_view_set_indent
(
GtkTextView *
text_view, gint indent);
gint gtk_text_view_get_indent
(
GtkTextView *
text_view);
void
gtk_text_view_set_tabs
(
GtkTextView *
text_view, PangoTabArray *
tabs);
PangoTabArray*
gtk_text_view_get_tabs
(
GtkTextView *
text_view);
GtkTextAttributes*
gtk_text_view_get_default_attributes
(
GtkTextView *
text_view);
GtkTextBuffer :
GtkTextBuffer*
gtk_text_buffer_new
(
GtkTextTagTable *
table);
gint gtk_text_buffer_get_line_count
(
GtkTextBuffer *
buffer);
gint gtk_text_buffer_get_char_count
(
GtkTextBuffer *
buffer);
GtkTextTagTable*
gtk_text_buffer_get_tag_table
(
GtkTextBuffer *
buffer);
void
gtk_text_buffer_insert_at_cursor
(
GtkTextBuffer *
buffer, const
gchar *
text, gint len);
gboolean gtk_text_buffer_insert_interactive
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
gchar *
text, gint len, gboolean default_editable);
gboolean gtk_text_buffer_insert_interactive_at_cursor
(
GtkTextBuffer *
buffer, const
gchar *
text, gint len, gboolean default_editable);
void
gtk_text_buffer_insert_range
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
GtkTextIter *
start, const
GtkTextIter *
end);
gboolean gtk_text_buffer_insert_range_interactive
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
GtkTextIter *
start, const
GtkTextIter *
end, gboolean default_editable);
void
gtk_text_buffer_insert_with_tags
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
gchar *
text, gint len, GtkTextTag *
first_tag, ...);
void
gtk_text_buffer_insert_with_tags_by_name
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, const
gchar *
text, gint len, const
gchar *
first_tag_name, ...);
gboolean gtk_text_buffer_delete_interactive
(
GtkTextBuffer *
buffer, GtkTextIter *
start_iter, GtkTextIter *
end_iter, gboolean default_editable);
void
gtk_text_buffer_set_text
(
GtkTextBuffer *
buffer, const
gchar *
text, gint len);
gchar*
gtk_text_buffer_get_slice
(
GtkTextBuffer *
buffer, const
GtkTextIter *
start, const
GtkTextIter *
end, gboolean include_hidden_chars);
void
gtk_text_buffer_insert_pixbuf
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, GdkPixbuf *
pixbuf);
void
gtk_text_buffer_insert_child_anchor
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, GtkTextChildAnchor *
anchor);
GtkTextChildAnchor*
gtk_text_buffer_create_child_anchor
(
GtkTextBuffer *
buffer, GtkTextIter *
iter);
GtkTextMark*
gtk_text_buffer_create_mark
(
GtkTextBuffer *
buffer, const
gchar *
mark_name, const
GtkTextIter *
where, gboolean left_gravity);
void
gtk_text_buffer_move_mark
(
GtkTextBuffer *
buffer, GtkTextMark *
mark, const
GtkTextIter *
where);
void
gtk_text_buffer_move_mark_by_name
(
GtkTextBuffer *
buffer, const
gchar *
name, const
GtkTextIter *
where);
void
gtk_text_buffer_delete_mark
(
GtkTextBuffer *
buffer, GtkTextMark *
mark);
void
gtk_text_buffer_delete_mark_by_name
(
GtkTextBuffer *
buffer, const
gchar *
name);
GtkTextMark*
gtk_text_buffer_get_mark
(
GtkTextBuffer *
buffer, const
gchar *
name);
GtkTextMark*
gtk_text_buffer_get_insert
(
GtkTextBuffer *
buffer);
GtkTextMark*
gtk_text_buffer_get_selection_bound
(
GtkTextBuffer *
buffer);
void
gtk_text_buffer_place_cursor
(
GtkTextBuffer *
buffer, const
GtkTextIter *
where);
void
gtk_text_buffer_apply_tag
(
GtkTextBuffer *
buffer, GtkTextTag *
tag, const
GtkTextIter *
start, const
GtkTextIter *
end);
void
gtk_text_buffer_remove_tag
(
GtkTextBuffer *
buffer, GtkTextTag *
tag, const
GtkTextIter *
start, const
GtkTextIter *
end);
void
gtk_text_buffer_apply_tag_by_name
(
GtkTextBuffer *
buffer, const
gchar *
name, const
GtkTextIter *
start, const
GtkTextIter *
end);
void
gtk_text_buffer_remove_tag_by_name
(
GtkTextBuffer *
buffer, const
gchar *
name, const
GtkTextIter *
start, const
GtkTextIter *
end);
void
gtk_text_buffer_remove_all_tags
(
GtkTextBuffer *
buffer, const
GtkTextIter *
start, const
GtkTextIter *
end);
GtkTextTag*
gtk_text_buffer_create_tag
(
GtkTextBuffer *
buffer, const
gchar *
tag_name, const
gchar *
first_property_name, ...);
void
gtk_text_buffer_get_iter_at_line_offset
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, gint line_number, gint char_offset);
void
gtk_text_buffer_get_iter_at_offset
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, gint char_offset);
void
gtk_text_buffer_get_iter_at_line
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, gint line_number);
void
gtk_text_buffer_get_iter_at_line_index
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, gint line_number, gint byte_index);
void
gtk_text_buffer_get_iter_at_mark
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, GtkTextMark *
mark);
void
gtk_text_buffer_get_iter_at_child_anchor
(
GtkTextBuffer *
buffer, GtkTextIter *
iter, GtkTextChildAnchor *
anchor);
void
gtk_text_buffer_get_bounds
(
GtkTextBuffer *
buffer, GtkTextIter *
start, GtkTextIter *
end);
gboolean gtk_text_buffer_get_modified
(
GtkTextBuffer *
buffer);
void
gtk_text_buffer_set_modified
(
GtkTextBuffer *
buffer, gboolean setting);
gboolean gtk_text_buffer_delete_selection
(
GtkTextBuffer *
buffer, gboolean interactive, gboolean default_editable);
void
gtk_text_buffer_paste_clipboard
(
GtkTextBuffer *
buffer, GtkClipboard *
clipboard, GtkTextIter *
override_location, gboolean default_editable);
void
gtk_text_buffer_copy_clipboard
(
GtkTextBuffer *
buffer, GtkClipboard *
clipboard);
void
gtk_text_buffer_cut_clipboard
(
GtkTextBuffer *
buffer, GtkClipboard *
clipboard, gboolean default_editable);
gboolean gtk_text_buffer_get_selection_bounds
(
GtkTextBuffer *
buffer, GtkTextIter *
start, GtkTextIter *
end);
void
gtk_text_buffer_begin_user_action
(
GtkTextBuffer *
buffer);
void
gtk_text_buffer_end_user_action
(
GtkTextBuffer *
buffer);
void
gtk_text_buffer_add_selection_clipboard
(
GtkTextBuffer *
buffer, GtkClipboard *
clipboard);
void
gtk_text_buffer_remove_selection_clipboard
(
GtkTextBuffer *
buffer, GtkClipboard *
clipboard);
GtkTextIter :
GtkTextBuffer*
gtk_text_iter_get_buffer
(
const
GtkTextIter *
iter);
GtkTextIter*
gtk_text_iter_copy
(
const
GtkTextIter *
iter);
void
gtk_text_iter_free
(
GtkTextIter *
iter);
gint gtk_text_iter_get_offset
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_line
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_line_offset
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_line_index
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_visible_line_index
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_visible_line_offset
(
const
GtkTextIter *
iter);
gunichar gtk_text_iter_get_char
(
const
GtkTextIter *
iter);
gchar*
gtk_text_iter_get_slice
(
const
GtkTextIter *
start, const
GtkTextIter *
end);
gchar*
gtk_text_iter_get_text
(
const
GtkTextIter *
start, const
GtkTextIter *
end);
gchar*
gtk_text_iter_get_visible_slice
(
const
GtkTextIter *
start, const
GtkTextIter *
end);
gchar*
gtk_text_iter_get_visible_text
(
const
GtkTextIter *
start, const
GtkTextIter *
end);
GdkPixbuf*
gtk_text_iter_get_pixbuf
(
const
GtkTextIter *
iter);
GSList*
gtk_text_iter_get_marks
(
const
GtkTextIter *
iter);
GSList*
gtk_text_iter_get_toggled_tags
(
const
GtkTextIter *
iter, gboolean toggled_on);
GtkTextChildAnchor*
gtk_text_iter_get_child_anchor
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_begins_tag
(
const
GtkTextIter *
iter, GtkTextTag *
tag);
gboolean gtk_text_iter_ends_tag
(
const
GtkTextIter *
iter, GtkTextTag *
tag);
gboolean gtk_text_iter_toggles_tag
(
const
GtkTextIter *
iter, GtkTextTag *
tag);
gboolean gtk_text_iter_has_tag
(
const
GtkTextIter *
iter, GtkTextTag *
tag);
GSList*
gtk_text_iter_get_tags
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_editable
(
const
GtkTextIter *
iter, gboolean default_setting);
gboolean gtk_text_iter_can_insert
(
const
GtkTextIter *
iter, gboolean default_editability);
gboolean gtk_text_iter_starts_word
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_ends_word
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_inside_word
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_starts_line
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_ends_line
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_starts_sentence
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_ends_sentence
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_inside_sentence
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_is_cursor_position
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_chars_in_line
(
const
GtkTextIter *
iter);
gint gtk_text_iter_get_bytes_in_line
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_get_attributes
(
const
GtkTextIter *
iter, GtkTextAttributes *
values);
PangoLanguage*
gtk_text_iter_get_language
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_is_end
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_is_start
(
const
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_char
(
GtkTextIter *
iter);
gboolean gtk_text_iter_backward_char
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_chars
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_backward_chars
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_forward_line
(
GtkTextIter *
iter);
gboolean gtk_text_iter_backward_line
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_lines
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_backward_lines
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_forward_word_ends
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_backward_word_starts
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_forward_word_end
(
GtkTextIter *
iter);
gboolean gtk_text_iter_backward_word_start
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_cursor_position
(
GtkTextIter *
iter);
gboolean gtk_text_iter_backward_cursor_position
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_cursor_positions
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_backward_cursor_positions
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_backward_sentence_start
(
GtkTextIter *
iter);
gboolean gtk_text_iter_backward_sentence_starts
(
GtkTextIter *
iter, gint count);
gboolean gtk_text_iter_forward_sentence_end
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_sentence_ends
(
GtkTextIter *
iter, gint count);
void
gtk_text_iter_set_offset
(
GtkTextIter *
iter, gint char_offset);
void
gtk_text_iter_set_line
(
GtkTextIter *
iter, gint line_number);
void
gtk_text_iter_set_line_offset
(
GtkTextIter *
iter, gint char_on_line);
void
gtk_text_iter_set_line_index
(
GtkTextIter *
iter, gint byte_on_line);
void
gtk_text_iter_set_visible_line_index
(
GtkTextIter *
iter, gint byte_on_line);
void
gtk_text_iter_set_visible_line_offset
(
GtkTextIter *
iter, gint char_on_line);
void
gtk_text_iter_forward_to_end
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_to_line_end
(
GtkTextIter *
iter);
gboolean gtk_text_iter_forward_to_tag_toggle
(
GtkTextIter *
iter, GtkTextTag *
tag);
gboolean gtk_text_iter_backward_to_tag_toggle
(
GtkTextIter *
iter, GtkTextTag *
tag);
gboolean (*
GtkTextCharPredicate)(
gunichar ch, gpointer user_data);
gboolean gtk_text_iter_forward_find_char
(
GtkTextIter *
iter, GtkTextCharPredicate pred, gpointer user_data, const
GtkTextIter *
limit);
gboolean gtk_text_iter_backward_find_char
(
GtkTextIter *
iter, GtkTextCharPredicate pred, gpointer user_data, const
GtkTextIter *
limit);
gboolean gtk_text_iter_forward_search
(
const
GtkTextIter *
iter, const
gchar *
str, GtkTextSearchFlags flags, GtkTextIter *
match_start, GtkTextIter *
match_end, const
GtkTextIter *
limit);
gboolean gtk_text_iter_backward_search
(
const
GtkTextIter *
iter, const
gchar *
str, GtkTextSearchFlags flags, GtkTextIter *
match_start, GtkTextIter *
match_end, const
GtkTextIter *
limit);
gboolean gtk_text_iter_equal
(
const
GtkTextIter *
lhs, const
GtkTextIter *
rhs);
gint gtk_text_iter_compare
(
const
GtkTextIter *
lhs, const
GtkTextIter *
rhs);
gboolean gtk_text_iter_in_range
(
const
GtkTextIter *
iter, const
GtkTextIter *
start, const
GtkTextIter *
end);
void
gtk_text_iter_order
(
GtkTextIter *
first, GtkTextIter *
second);
XXII. Les pages à onglets▲
Nous allons étudier dans ce chapitre les pages à onglets qui sont souvent utilisées dans les fenêtres de configuration. Pour cela nous allons utiliser le widget GtkNotebook qui dérive du widget GtkContainer.
XXII-A. Utilisation du widget GtkNotebook▲
XXII-A-1. 1.1 Création▲
Pour ne pas changer, la création du widget en lui-même est très simple :
GtkWidget*
gtk_notebook_new
(
void
);
Maintenant que notre widget est créé, nous allons lui ajouter des pages.
XXII-A-2. Insertion de pages▲
Nous avons là aussi trois fonctions qui restent très classiques :
void
gtk_notebook_append_page
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label);
void
gtk_notebook_prepend_page
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label);
void
gtk_notebook_insert_page
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label, gint position);
La première fonction ajoute une nouvelle page à onglet à la suite des autres, la deuxième fonction l'ajoute au début, et la dernière l'ajoute à une position particulière.
Le premier paramètre, notebook, est bien sûr le GtkNotebook dans lequel nous voulons ajouter la page. Il faudra utiliser la macro de conversion GTK_NOTEBOOK().
Le second, child, est le widget qui sera inséré dans la nouvelle page, et le troisième (tab_label) le widget qui sera affiché dans l'onglet.
La troisième fonction demande un paramètre supplémentaire (position) qui est la position à laquelle il faut ajouter la page. Si la valeur n'est pas correcte (négative ou trop grande) la page sera ajoutée à la suite des autres.
XXII-A-3. Gestion des pages▲
Nous allons maintenant voir les fonctions qui permettent de connaître le nombre de pages, la page en cours et d'autres fonctions.
Tout d'abord, la fonction suivante permet de connaître le nombre total de pages contenues dans le GtkNotebook :
gint gtk_notebook_get_n_pages
(
GtkNotebook *
notebook);
Ensuite, pour connaître le numéro de la page courante, nous avons cette fonction :
gint gtk_notebook_get_current_page
(
GtkNotebook *
notebook);
Par contre pour connaître le numéro d'une autre page que la courante, il faudra utiliser cette fonction :
gint gtk_notebook_page_num
(
GtkNotebook *
notebook, GtkWidget *
child);
Cette fonction permet d'obtenir le numéro de la page contenant le widget child, ce qui impose donc d'avoir gardé une trace de ce widget pour pouvoir utiliser cette fonction.
Avec ce numéro de page, nous allons pouvoir récupérer un pointeur sur le widget qui est contenu dans la page avec cette fonction :
GtkWidget*
gtk_notebook_get_nth_page
(
GtkNotebook *
notebook, gint page_num);
Ou bien nous allons pouvoir tout simplement supprimer la page :
void
gtk_notebook_remove_page
(
GtkNotebook *
notebook, gint page_num);
Et pour terminer, voici trois fonctions de navigation :
void
gtk_notebook_next_page
(
GtkNotebook *
notebook);
void
gtk_notebook_prev_page
(
GtkNotebook *
notebook);
void
gtk_notebook_set_current_page
(
GtkNotebook *
notebook, gint page_num);
La première fonction passe de la page courante à la page suivante. Si la dernière page est déjà affichée, il ne se passera rien.
La deuxième fonction, elle, passe de la page courante à la page précédente. Bien entendu, si la page courante est déjà la première cette fonction n'aura aucun effet.
La dernière fonction quant à elle passe directement à une page précise. Si la valeur de page_num est négative, nous passerons à la dernière page, par contre si cette valeur est trop grande, aucune action ne sera faite.
XXII-A-4. Gestion des labels▲
Nous allons maintenant voir comment modifier ou récupérer le label d'une page. Attention pour chacune de ces fonctions, il faut connaître le widget contenu dans la page.
Tout d'abord, pour récupérer le label de la page, il existe deux fonctions différentes :
G_CONST_RETURN gchar*
gtk_notebook_get_tab_label_text
(
GtkNotebook *
notebook, GtkWidget *
child);
GtkWidget*
gtk_notebook_get_tab_label
(
GtkNotebook *
notebook, GtkWidget *
child);
La première fonction renvoie directement le label de la page sous la forme d'un gchar*. Cette fonction fonctionnera correctement uniquement si le label de la page est un GtkLabel, car comme nous l'avons lors de l'étude des fonctions d'insertion des pages, il est possible de définir le label comme autre chose qu'un GtkLabel. Dans ce cas, il faut utiliser la deuxième fonction qui elle renvoie le widget qui a été utilisé lors de la création.
Pour définir un nouveau label pour une page, il existe là aussi deux fonctions :
void
gtk_notebook_set_tab_label_text
(
GtkNotebook *
notebook, GtkWidget *
child, const
gchar *
tab_text);
void
gtk_notebook_set_tab_label
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label);
La première fonction permet de définir un label de type GtkLabel. Cette fonction s'occupe de la création du GtkLabel et de son insertion dans l'onglet de la page. La deuxième fonction permet d'insérer n'importe quel widget dans l'onglet, comme pour les fonctions de création. Dans les deux cas, si les paramètres tab_text ou tab_label sont définis comme NULL, le label de la page sera « Page y », y étant le numéro de la page.
XXII-A-5. Modification des propriétés du GtkNotebook▲
Nous allons maintenant voir comment modifier trois des propriétés d'un GtkNotebook. Tout d'abord, voyons comment gérer la position des onglets :
void
gtk_notebook_set_tab_pos
(
GtkNotebook *
notebook, GtkPositionType pos);
GtkPositionType gtk_notebook_get_tab_pos
(
GtkNotebook *
notebook);
La première fonction permet de modifier la position des onglets. C'est le paramètre pos qui définit sa position, et il doit prendre une des valeurs suivantes :
- GTK_POS_LEFT pour les mettre à gauche ;
- GTK_POS_RIGHT pour les mettre à droite ;
- GTK_POS_TOP pour les mettre en haut ;
- GTK_POS_BOTTOM pour les mettre en bas.
La deuxième fonction permet au contraire de connaître la position des onglets. La valeur de retour est obligatoirement une des quatre valeurs précédentes.
Ensuite nous allons pouvoir définir si les onglets doivent s'afficher ou pas avec ces fonctions :
void
gtk_notebook_set_show_tabs
(
GtkNotebook *
notebook, gboolean show_tabs);
gboolean gtk_notebook_get_show_tabs
(
GtkNotebook *
notebook);
Si nous voulons modifier ce paramètre, il faut utiliser la première fonction en mettant le paramètre show_tabs à TRUE pour les afficher et à FALSE dans le cas contraire. La deuxième fonction permet quant à elle de connaître l'état de cette propriété.
Et enfin, pour terminer nous allons voir comment ajouter deux boutons de navigation à la fin des onglets, pour le cas où il y aurait trop d'onglets à afficher :
void
gtk_notebook_set_scrollable
(
GtkNotebook *
notebook, gboolean scrollable);
gboolean gtk_notebook_get_scrollable
(
GtkNotebook *
notebook);
Si nous mettons le paramètre scrollable de la première fonction à TRUE, deux boutons de navigation apparaîtront et une partie seulement des onglets sera affichée. Pour accéder aux autres onglets, il faudra utiliser ces nouveaux boutons.
Bien entendu, la deuxième fonction permet de savoir si les boutons de navigation sont présents ou pas.
XXII-A-6. Exemple▲
Nous allons créer un programme qui insèrera un GtkNotebook de 8 pages dans une fenêtre. Chaque page contiendra uniquement un label « Je suis le GtkLabel numero x ». Il y a aussi un bouton qui permettra d'afficher les informations de la page sélectionnée dans une boite de dialogue.
XXII-A-7. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnButton
(
GtkWidget *
pButton, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pNotebook;
GtkWidget *
pButton;
gint i;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkNotebook
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
pButton =
gtk_button_new_with_label
(
"
Informations
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton, FALSE, FALSE, 0
);
/* Creation du GtkNotebook */
pNotebook =
gtk_notebook_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pNotebook, TRUE, TRUE, 0
);
/* Position des onglets : en bas */
gtk_notebook_set_tab_pos
(
GTK_NOTEBOOK
(
pNotebook), GTK_POS_BOTTOM);
/* Ajout des boutons de navigation */
gtk_notebook_set_scrollable
(
GTK_NOTEBOOK
(
pNotebook), TRUE);
for
(
i =
0
; i <
8
; ++
i)
{
GtkWidget *
pLabel;
GtkWidget *
pTabLabel;
gchar *
sLabel;
gchar *
sTabLabel;
sLabel =
g_strdup_printf
(
"
Je suis le GtkLabel numero %d
"
, i);
sTabLabel =
g_strdup_printf
(
"
Page %d
"
, i);
/* Creation des differents GtkLabel */
pLabel =
gtk_label_new
(
sLabel);
pTabLabel =
gtk_label_new
(
sTabLabel);
/* Insertion de la page */
gtk_notebook_append_page
(
GTK_NOTEBOOK
(
pNotebook), pLabel, pTabLabel);
g_free
(
sLabel);
g_free
(
sTabLabel);
}
g_signal_connect
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
OnButton), pNotebook);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnButton
(
GtkWidget *
pButton, gpointer data)
{
GtkWidget *
pDialog;
GtkWidget *
pChild;
gint iPageNum;
const
gchar *
sLabel;
const
gchar *
sTabLabel;
gchar *
sDialogText;
/* Recuperation de la page active */
iPageNum =
gtk_notebook_get_current_page
(
GTK_NOTEBOOK
(
data));
/* Recuperation du widget enfant */
pChild =
gtk_notebook_get_nth_page
(
GTK_NOTEBOOK
(
data), iPageNum);
/* Recuperation du label */
sLabel =
gtk_label_get_text
(
GTK_LABEL
(
pChild));
/* Recuperation du label de l'onglet */
sTabLabel =
gtk_notebook_get_tab_label_text
(
GTK_NOTEBOOK
(
data), pChild);
/* Creation du label de la boite de dialogue */
sDialogText =
g_strdup_printf
(
"
C'est la page %d
\n
"
"
Le label est
\"
%s
\"\n
"
"
Le label de l'onglet est
\"
%s
\"\n
"
,
iPageNum,
sLabel,
sTabLabel);
pDialog =
gtk_message_dialog_new
(
NULL
,
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
sDialogText);
gtk_dialog_run
(
GTK_DIALOG
(
pDialog));
gtk_widget_destroy
(
pDialog);
g_free
(
sDialogText);
}
Résultat :
XXII-B. Ajouter un menu de navigation▲
Nous allons maintenant voir comment ajouter un menu qui apparaîtra lorsque nous ferons un clic droit de la souris sur une page du GtkNotebook. Cela ne se fait pas par le biais du widget GtkMenu, mais directement avec les fonctions de GtkNotebook.
XXII-B-1. Création▲
Pour avoir un GtkNotebook avec un menu de navigation, trois nouvelles fonctions de création sont disponibles :
void
gtk_notebook_append_page_menu
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label, GtkWidget *
menu_label);
void
gtk_notebook_prepend_page_menu
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label, GtkWidget *
menu_label);
void
gtk_notebook_insert_page_menu
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
tab_label, GtkWidget *
menu_label, gint position);
La majorité des paramètres de ces trois fonctions sont identiques sauf pour le paramètre menu_label qui est le widget qui sera affiché dans le menu de navigation. Le fonctionnement de ces fonctions est le même que pour les fonctions sans menu.
Ensuite pour activer ou désactiver la possibilité d'afficher le menu il faut utiliser une de ces fonctions :
void
gtk_notebook_popup_enable
(
GtkNotebook *
notebook);
void
gtk_notebook_popup_disable
(
GtkNotebook *
notebook);
La première fonction permet d'afficher le menu, et la deuxième au contraire empêche le menu de s'afficher.
XXII-B-2. Gestion des labels▲
Comme pour les onglets, il existe des fonctions pour gérer les labels du menu. Pour récupérer le widget ou directement le texte du menu, nous avons ces deux fonctions :
GtkWidget*
gtk_notebook_get_menu_label
(
GtkNotebook *
notebook, GtkWidget *
child);
G_CONST_RETURN gchar*
gtk_notebook_get_menu_label_text
(
GtkNotebook *
notebook, GtkWidget *
child);
La première fonction renvoie donc le widget, quel qu'il soit, qui est à l'intérieur du menu alors que la seconde renvoie le texte du menu si l'élément est de type GtkLabel.
Et pour changer le label du menu, il existe ces deux fonctions :
void
gtk_notebook_set_menu_label
(
GtkNotebook *
notebook, GtkWidget *
child, GtkWidget *
menu_label);
void
gtk_notebook_set_menu_label_text
(
GtkNotebook *
notebook, GtkWidget *
child, const
gchar *
menu_text);
La première accepte n'importe quel type de widget, tandis que la seconde crée elle-même un widget de type GtkLabel avec comme texte la valeur du paramètre menu_text.
XXII-B-3. Exemple▲
Nous allons reprendre le même exemple que pour la première partie en rajoutant le menu de navigation.
XXII-B-4. Programme exemple▲
#include <stdlib.h>
#include <gtk/gtk.h>
void
OnButton
(
GtkWidget *
pButton, gpointer data);
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pVBox;
GtkWidget *
pNotebook;
GtkWidget *
pButton;
gint i;
gtk_init
(&
argc,&
argv);
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkNotebook
"
);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
pVBox =
gtk_vbox_new
(
FALSE, 0
);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pVBox);
pButton =
gtk_button_new_with_label
(
"
Informations
"
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pButton, FALSE, FALSE, 0
);
/* Creation du GtkNotebook */
pNotebook =
gtk_notebook_new
(
);
gtk_box_pack_start
(
GTK_BOX
(
pVBox), pNotebook, TRUE, TRUE, 0
);
/* Position des onglets : en bas */
gtk_notebook_set_tab_pos
(
GTK_NOTEBOOK
(
pNotebook), GTK_POS_BOTTOM);
/* Ajout des boutons de navigation */
gtk_notebook_set_scrollable
(
GTK_NOTEBOOK
(
pNotebook), TRUE);
for
(
i =
0
; i <
8
; ++
i)
{
GtkWidget *
pLabel;
GtkWidget *
pTabLabel;
GtkWidget *
pMenuLabel;
gchar *
sLabel;
gchar *
sTabLabel;
gchar *
sMenuLabel;
sLabel =
g_strdup_printf
(
"
Je suis le GtkLabel numero %d
"
, i);
sTabLabel =
g_strdup_printf
(
"
Page %d
"
, i);
sMenuLabel =
g_strdup_printf
(
"
Menu -> Page %d
"
, i);
/* Creation des differents GtkLabel */
pLabel =
gtk_label_new
(
sLabel);
pTabLabel =
gtk_label_new
(
sTabLabel);
pMenuLabel =
gtk_label_new
(
sMenuLabel);
/* Insertion de la page */
gtk_notebook_append_page_menu
(
GTK_NOTEBOOK
(
pNotebook), pLabel, pTabLabel, pMenuLabel);
g_free
(
sLabel);
g_free
(
sTabLabel);
g_free
(
sMenuLabel);
}
/* Activation du menu popup */
gtk_notebook_popup_enable
(
GTK_NOTEBOOK
(
pNotebook));
g_signal_connect
(
G_OBJECT
(
pButton), "
clicked
"
, G_CALLBACK
(
OnButton), pNotebook);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
void
OnButton
(
GtkWidget *
pButton, gpointer data)
{
GtkWidget *
pDialog;
GtkWidget *
pChild;
gint iPageNum;
const
gchar *
sLabel;
const
gchar *
sTabLabel;
const
gchar *
sMenuLabel;
gchar *
sDialogText;
/* Recuperation de la page active */
iPageNum =
gtk_notebook_get_current_page
(
GTK_NOTEBOOK
(
data));
/* Recuperation du widget enfant */
pChild =
gtk_notebook_get_nth_page
(
GTK_NOTEBOOK
(
data), iPageNum);
/* Recuperation du label */
sLabel =
gtk_label_get_text
(
GTK_LABEL
(
pChild));
/* Recuperation du label de l'onglet */
sTabLabel =
gtk_notebook_get_tab_label_text
(
GTK_NOTEBOOK
(
data), pChild);
/* Recuperation du label du menu popup */
sMenuLabel =
gtk_notebook_get_menu_label_text
(
GTK_NOTEBOOK
(
data), pChild);
/* Creation du label de la boite de dialogue */
sDialogText =
g_strdup_printf
(
"
C'est la page %d
\n
"
"
Le label est
\"
%s
\"\n
"
"
Le label de l'onglet est
\"
%s
\"\n
"
"
Le label du menu est
\"
%s
\"\n
"
,
iPageNum,
sLabel,
sTabLabel,
sMenuLabel);
pDialog =
gtk_message_dialog_new
(
NULL
,
GTK_DIALOG_MODAL,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
sDialogText);
gtk_dialog_run
(
GTK_DIALOG
(
pDialog));
gtk_widget_destroy
(
pDialog);
g_free
(
sDialogText);
}
Résultat :
XXII-C. En savoir plus▲
XXII-C-1. Les signaux▲
Prototypes fonctions callback :
-
change-current-page
Sélectionnezvoid
user_function
(
GtkNotebook*
notebook, gint arg1, gpointer user_data); -
focus-tab
Sélectionnezgboolean
user_function
(
GtkNotebook*
notebook, GtkNotebookTab arg1, gpointer user_data); -
move-focus-out
Sélectionnezvoid
user_function
(
GtkNotebook*
notebook, GtkDirectionType arg1, gpointer user_data); -
select-page
Sélectionnezgboolean
user_function
(
GtkNotebook*
notebook, gboolean arg1, gpointer user_data); - switch-page
void
user_function
(
GtkNotebook *
notebook, GtkNotebookPage *
page, guint page_num, gpointer user_data);
XXII-C-2. Fonctions non documentées▲
void
gtk_notebook_reorder_child
(
GtkNotebook *
notebook, GtkWidget *
child, gint position);
void
gtk_notebook_set_show_border
(
GtkNotebook *
notebook, gboolean show_border);
gboolean gtk_notebook_get_show_border
(
GtkNotebook *
notebook);
void
gtk_notebook_query_tab_label_packing
(
GtkNotebook *
notebook, GtkWidget *
child, gboolean *
expand, gboolean *
fill, GtkPackType *
pack_type);
void
gtk_notebook_set_tab_label_packing
(
GtkNotebook *
notebook, GtkWidget *
child, gboolean expand, gboolean fill, GtkPackType pack_type);
XXIII. Le widget GtkTreeView▲
Nous allons étudier dans ce chapitre comment afficher des données sous forme de liste ou d'arbre. Le widget GtkTreeView utilise plusieurs widgets pour permettre l'affichage de données.
XXIII-A. Introduction▲
L'utilisation de ce widget se décompose en deux parties distinctes :
- la création du modèle ;
- la gestion de l'affichage.
La création du modèle se fait soit par l'utilisation de GtkListStore pour créer une liste, soit par GtkTreeStore pour la création d'un arbre. C'est deux objets stockent dans un premier temps la structure des données, c'est-à-dire le nombre de colonnes, le type d'affichage (texte, image, case à cocher) et stockent dans un second temps les données qui seront affichées par la suite.
Une fois le modèle créé, nous pouvons passer à la partie affichage des données. Le widget principal est bien sûr GtkTreeView qui utilise dans un premier temps l'objet GtkTreeViewColumn qui servira à définir chaque colonne du widget. Et enfin pour chaque colonne il faut définir le type d'affichage à l'aide des objets GtkCellRendererText (pour afficher du texte), GtkCellRendererPixbuf (pour afficher une image) et GtkCellRenderToggle (pour afficher une case à cocher).
Regardons maintenant comment coder cela.
XXIII-B. Création d'une liste▲
XXIII-B-1. Création▲
Pour créer un modèle de type liste, nous allons utiliser cette fonction :
GtkListStore*
gtk_list_store_new
(
gint n_columns, ...);
Le premier paramètre de cette fonction définit le nombre de colonnes du modèle et donc du GtkTreeView. À la suite de ce paramètre, il faut définir le type de donnée qui sera stockée dans chaque colonne. Les types les plus communs sont :
- G_TYPE_STRING pour afficher une chaîne de caractère ;
- G_TYPE_BOOLEAN pour utiliser une case à cocher ;
- G_TYPE_INT pour afficher un entier ;
- G_TYPE_FLOAT pour afficher un float ;
- G_TYPE_DOUBLE pour afficher un double ;
- GDK_TYPE_PIXBUF pour afficher une image.
Une fois que les différentes colonnes sont définies, nous allons voir comment ajouter des éléments à la liste.
XXIII-B-2. Insertion d'éléments▲
La première étape de l'insertion consiste à créer une nouvelle entrée (ligne) à la liste. Pour cela, nous allons utiliser l'objet GtkTreeIter. Cet objet permet de savoir à quel endroit nous nous positionnons dans la liste. La création d'une nouvelle ligne va donner une nouvelle position dont nous avons besoin pour entrer les données.
Voici la liste des fonctions qui permettent de créer une nouvelle entrée :
void
gtk_list_store_append
(
GtkListStore *
list_store, GtkTreeIter *
iter);
void
gtk_list_store_prepend
(
GtkListStore *
list_store, GtkTreeIter *
iter);
void
gtk_list_store_insert
(
GtkListStore *
list_store, GtkTreeIter *
iter, gint position);
void
gtk_list_store_insert_before
(
GtkListStore *
list_store, GtkTreeIter *
iter, GtkTreeIter *
sibling);
void
gtk_list_store_insert_after
(
GtkListStore *
list_store, GtkTreeIter *
iter, GtkTreeIter *
sibling);
Pour chacune de ces fonctions, le premier paramètre list_store est la liste qui a été créée précédemment et le deuxième paramètre iter, est la position de la ligne nouvellement créée.
Les deux premières fonctions sont les plus couramment utilisées lors de la création de la liste. La première fonction crée une nouvelle ligne à la fin de la liste tandis que la deuxième fonction l'ajoute au début de la liste.
Les trois fonctions suivantes permettent d'introduire une nouvelle ligne à une position bien précise. La troisième fonction l'ajoute par rapport à une valeur numérique (paramètre position), la quatrième fonction l'ajoute avant une ligne bien définie par son itération sibling et la cinquième fonction l'ajoute après une ligne définie de la même manière.
Il faut maintenant définir le contenu de la nouvelle ligne, en utilisant cette unique fonction :
void gtk_list_store_set(GtkListStore *list_store, GtkTreeIter *iter…);
Les paramètres list_store et iter sont bien sûr la liste et la ligne pour laquelle nous voulons spécifier les données. À la suite de ces deux paramètres, il suffit d'ajouter les différentes données avec dans l'ordre la colonne de la donnée suivie de sa valeur. Et pour terminer, il faut dire à cette fonction que la liste des données est terminée simplement en ajoutant -1 en dernier paramètre.
La liste est maintenant prête à l'affichage.
XXIII-C. Création d'un arbre▲
Nous allons maintenant voir les légères différences qu'il y a entre la création d'une liste et la création d'un arbre à l'aide de l'objet GtkTreeStore. La principale différence est que chaque ligne peut avoir une ligne parente et une ou plusieurs lignes enfants. Nous n'avons donc plus affaire à une simple succession de lignes, mais à une organisation imbriquée de succession de lignes.
XXIII-C-1. Création▲
La fonction de création est très ressemblante à celle de l'objet GtkListStore :
GtkTreeStore*
gtk_tree_store_new
(
gint n_columns, ...);
Bien entendu, le paramètre n_columns est le nombre de colonnes de chaque ligne de l'arbre, suivi des différents types des données.
XXIII-C-2. Insertion d'éléments▲
Cette fois aussi les fonctions sont presque identiques à celles fournies pour les listes :
void
gtk_tree_store_append
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, GtkTreeIter *
parent);
void
gtk_tree_store_prepend
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, GtkTreeIter *
parent);
void
gtk_tree_store_insert
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, GtkTreeIter *
parent, gint position);
void
gtk_tree_store_insert_before
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, GtkTreeIter *
parent, GtkTreeIter *
sibling);
void
gtk_tree_store_insert_after
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, GtkTreeIter *
parent, GtkTreeIter *
sibling);
La grande nouveauté, avec toutes ces fonctions, est la présence d'un paramètre supplémentaire, parent, de type GtkTreeIter, qui n'est autre que la ligne dont notre nouvel élément sera l'enfant.
Si notre nouvelle ligne n'a pas de parent, ce paramètre sera à NULL, sinon il faudra mettre l'itération correspondant à la ligne parente.
Et pour finir, il faut définir les valeurs de chaque colonne grâce à cette fonction :
void
gtk_tree_store_set
(
GtkTreeStore *
tree_store, GtkTreeIter *
iter, ...);
De la même façon que pour les éléments de type GtkListStore, la liste de valeurs doit se terminer par -1.
XXIII-D. Affichage du widget GtkTreeView▲
Maintenant que le modèle du widget GtkTreeView a été créé, il faut gérer l'affichage de celui-ci. Cela va se dérouler en deux étapes distinctes :
- création de la vue ;
- création des colonnes.
Le déroulement de ces différentes étapes est identique que cela soit avec un modèle de type GtkListStore qu'avec un modèle de type GtkTreeStore.
XXIII-D-1. Création de la vue▲
Il existe deux fonctions de création du widget GtkTreeView :
GtkWidget*
gtk_tree_view_new
(
void
);
GtkWidget*
gtk_tree_view_new_with_model
(
GtkTreeModel *
model);
La première fonction crée une vue vide, alors que la deuxième fonction créera la vue à partir du modèle spécifié. Que l'on utilise un GtkListStore ou un GtkTreeStore, il faudra utiliser la macro GTK_TREE_MODEL pour spécifier le paramètre model.
Si la première fonction est utilisée pour la création de la vue, il faudra tout de même donner à la vue un modèle bien précis, pour que lors de l'affichage GTK+ sache quelles données il doit afficher, avec cette fonction :
void
gtk_tree_view_set_model
(
GtkTreeView *
tree_view, GtkTreeModel *
model);
XXIII-D-2. Création des colonnes▲
Lors de cette étape, nous allons introduire deux nouveaux objets. Tout d'abord l'objet GtkCellRenderer et ses dérivés, puis l'objet GtkTreeViewColumn. Nous allons donc maintenant voir comment ajouter les différentes colonnes à notre vue et aussi de quelle manière doit être fait le rendu.
La manière dont les cases d'une colonne sont rendues se définit à l'aide des objets dérivés de GtkCellRenderer :
- GtkCellRendererText pour afficher du texte ;
- GtkCellRendererToggle pour afficher une case à cocher ou un bouton radio ;
- GtkCellRendererPixbuf pour afficher une image.
Pour créer un de ces objets, nous avons les fonctions suivantes :
GtkCellRenderer*
gtk_cell_renderer_text_new
(
void
);
GtkCellRenderer*
gtk_cell_renderer_toggle_new
(
void
);
GtkCellRenderer*
gtk_cell_renderer_pixbuf_new
(
void
);
Une fois le GtkCellRenderer créé, nous pouvons modifier différents paramètres à l'aide de cette fonction :
void
g_object_set
(
gpointer object, const
gchar *
first_property_name, ...);
Le premier paramètre, object, est l'objet que l'on veut modifier. Il faut utiliser pour ce paramètre la macro G_OBJECT(). Puis, les paramètres suivants vont par couple paramètre/valeur pour modifier par exemple la couleur de fond de la case ou autre. Une fois tous les paramètres à modifier entrés, il faut ajouter NULL pour dire que la liste des modifications à apporter est terminée.
La liste des paramètres que nous pouvons modifier pour les objets de types GtkCellRenderer est disponible dans la section « En savoir plus » de ce chapitre.
Maintenant que nous savons comment les cases d'une colonne doivent être rendues, nous allons voir comment créer une colonne et comment l'ajouter à la vue. Pour créer une colonne, nous avons cette fonction :
GtkTreeViewColumn*
gtk_tree_view_column_new_with_attributes
(
const
gchar *
title, GtkCellRenderer *
cell, ...);
Le premier paramètre, title, est le texte qui sera affiché en haut de la colonne dans une ligne bien spécifique. Le second paramètre, cell, est simplement l'objet GtkCellRenderer que nous venons juste de créer, définissant le rendu de chaque case de la colonne.
Ensuite, il faut à nouveau définir le type de la colonne ainsi que le numéro de la colonne dans le modèle. Les types de colonnes sont « text » pour du texte, « active » pour une case à cocher, « pixbuf » pour une image.
Et pour terminer, comme souvent dans ce type de fonction, il faut ajouter NULL à la suite de tous les paramètres pour dire que la liste est terminée.
Il ne nous reste plus qu'à ajouter la colonne à la vue avec l'une de ces fonctions :
gint gtk_tree_view_append_column
(
GtkTreeView *
tree_view, GtkTreeViewColumn *
column);
gint gtk_tree_view_insert_column
(
GtkTreeView *
tree_view, GtkTreeViewColumn *
column, gint position);
La première fonction ajoute la colonne à la suite des autres, tandis que la seconde l'ajoute à la position position ou à la suite des autres si la valeur de position est invalide. La macro GTK_TREE_VIEW() est à utiliser pour le premier paramètre.
XXIII-D-3. Exemples▲
Nous allons créer deux exemples pour montrer l'utilisation du widget GtkTreeView. Dans le premier exemple, nous allons créer une liste avec simplement une colonne avec du texte et une colonne comportant une case à cocher. Le deuxième exemple, utilisera quant à lui un arbre avec une première colonne affichant une image, et du texte dans la deuxième colonne.
XXIII-D-4. Programme exemple 1▲
#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
enum
{
TEXT_COLUMN,
TOGGLE_COLUMN,
N_COLUMN
}
;
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pListView;
GtkWidget *
pScrollbar;
GtkListStore *
pListStore;
GtkTreeViewColumn *
pColumn;
GtkCellRenderer *
pCellRenderer;
gchar *
sTexte;
gint i;
gtk_init
(&
argc, &
argv);
/* Creation de la fenetre principale */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkTreeView et GtkListStore
"
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Creation du modele */
pListStore =
gtk_list_store_new
(
N_COLUMN, G_TYPE_STRING, G_TYPE_BOOLEAN);
sTexte =
g_malloc
(
12
);
/* Insertion des éléments */
for
(
i =
0
; i <
10
; ++
i)
{
GtkTreeIter pIter;
sprintf
(
sTexte, "
Ligne %d
\0
"
, i);
/* Creation de la nouvelle ligne */
gtk_list_store_append
(
pListStore, &
pIter);
/* Mise a jour des donnees */
gtk_list_store_set
(
pListStore, &
pIter,
TEXT_COLUMN, sTexte,
TOGGLE_COLUMN, TRUE,
-
1
);
}
g_free
(
sTexte);
/* Creation de la vue */
pListView =
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
pListStore));
/* Creation de la premiere colonne */
pCellRenderer =
gtk_cell_renderer_text_new
(
);
pColumn =
gtk_tree_view_column_new_with_attributes
(
"
Titre
"
,
pCellRenderer,
"
text
"
, TEXT_COLUMN,
NULL
);
/* Ajout de la colonne à la vue */
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
pListView), pColumn);
/* Creation de la deuxieme colonne */
pCellRenderer =
gtk_cell_renderer_toggle_new
(
);
pColumn =
gtk_tree_view_column_new_with_attributes
(
"
CheckBox
"
,
pCellRenderer,
"
active
"
, TOGGLE_COLUMN,
NULL
);
/* Ajout de la colonne à la vue */
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
pListView), pColumn);
/* Ajout de la vue a la fenetre */
pScrollbar =
gtk_scrolled_window_new
(
NULL
, NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
pScrollbar),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add
(
GTK_CONTAINER
(
pScrollbar), pListView);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pScrollbar);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XXIII-D-5. Programme exemple 2▲
#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
enum
{
BMP_COLUMN,
TEXT_COLUMN,
N_COLUMN
}
;
/* Utilisateurs Visual C++ : il faut ajouter gdk_pixbuf-2.0.lib dans les options du linker */
int
main
(
int
argc, char
**
argv)
{
GtkWidget *
pWindow;
GtkWidget *
pTreeView;
GtkWidget *
pScrollbar;
GtkTreeStore *
pTreeStore;
GtkTreeViewColumn *
pColumn;
GtkCellRenderer *
pCellRenderer;
GdkPixbuf *
pPixBufA;
GdkPixbuf *
pPixBufB;
gchar *
sTexte;
gint i;
gtk_init
(&
argc, &
argv);
/* Creation de la fenetre principale */
pWindow =
gtk_window_new
(
GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size
(
GTK_WINDOW
(
pWindow), 320
, 200
);
gtk_window_set_title
(
GTK_WINDOW
(
pWindow), "
GtkTreeView et GtkTreeStore
"
);
g_signal_connect
(
G_OBJECT
(
pWindow), "
destroy
"
, G_CALLBACK
(
gtk_main_quit), NULL
);
/* Creation du modele */
pTreeStore =
gtk_tree_store_new
(
N_COLUMN, GDK_TYPE_PIXBUF, G_TYPE_STRING);
sTexte =
g_malloc
(
16
);
/* Chargement des images */
pPixBufA =
gdk_pixbuf_new_from_file
(
"
./icon_computer.png
"
, NULL
);
pPixBufB =
gdk_pixbuf_new_from_file
(
"
./icon_directory.png
"
, NULL
);
/* Insertion des éléments */
for
(
i =
0
; i <
10
; ++
i)
{
GtkTreeIter pIter;
GtkTreeIter pIter2;
gint j;
sprintf
(
sTexte, "
Ordinateur %d
"
, i);
/* Creation de la nouvelle ligne */
gtk_tree_store_append
(
pTreeStore, &
pIter, NULL
);
/* Mise a jour des donnees */
gtk_tree_store_set
(
pTreeStore, &
pIter,
BMP_COLUMN, pPixBufA,
TEXT_COLUMN, sTexte,
-
1
);
for
(
j =
0
; j <
2
; ++
j)
{
sprintf
(
sTexte, "
Repertoire %d
"
, j);
/* Creation de la nouvelle ligne enfant */
gtk_tree_store_append
(
pTreeStore, &
pIter2, &
pIter);
/* Mise a jour des donnees */
gtk_tree_store_set
(
pTreeStore, &
pIter2,
BMP_COLUMN, pPixBufB,
TEXT_COLUMN, sTexte,
-
1
);
}
}
g_free
(
sTexte);
g_object_unref
(
pPixBufA);
g_object_unref
(
pPixBufB);
/* Creation de la vue */
pTreeView =
gtk_tree_view_new_with_model
(
GTK_TREE_MODEL
(
pTreeStore));
/* Creation de la premiere colonne */
pCellRenderer =
gtk_cell_renderer_pixbuf_new
(
);
pColumn =
gtk_tree_view_column_new_with_attributes
(
"
Image
"
,
pCellRenderer,
"
pixbuf
"
, BMP_COLUMN,
NULL
);
/* Ajout de la colonne à la vue */
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
pTreeView), pColumn);
/* Creation de la deuxieme colonne */
pCellRenderer =
gtk_cell_renderer_text_new
(
);
pColumn =
gtk_tree_view_column_new_with_attributes
(
"
Label
"
,
pCellRenderer,
"
text
"
, TEXT_COLUMN,
NULL
);
/* Ajout de la colonne à la vue */
gtk_tree_view_append_column
(
GTK_TREE_VIEW
(
pTreeView), pColumn);
/* Ajout de la vue a la fenetre */
pScrollbar =
gtk_scrolled_window_new
(
NULL
, NULL
);
gtk_scrolled_window_set_policy
(
GTK_SCROLLED_WINDOW
(
pScrollbar),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add
(
GTK_CONTAINER
(
pScrollbar), pTreeView);
gtk_container_add
(
GTK_CONTAINER
(
pWindow), pScrollbar);
gtk_widget_show_all
(
pWindow);
gtk_main
(
);
return
EXIT_SUCCESS;
}
Résultat :
XXIII-E. En savoir plus▲
XXIII-E-1. Les propriétés▲
GtkTreeView
Propriété |
Type |
Accès |
---|---|---|
enable-search |
gboolean |
Lecture/Ecriture |
expander-column |
GtkTreeViewColumn |
Lecture/Ecriture |
hadjustment |
GtkAdjustment |
Lecture/Ecriture |
headers-clickable |
gboolean |
Ecriture |
headers-visible |
gboolean |
Lecture/Ecriture |
model |
GtkTreeMode |
Lecture/Ecriture |
reorderable |
gboolean |
Lecture/Ecriture |
rules-hint |
gboolean |
Lecture/Ecriture |
search-column |
gint |
Lecture/Ecriture |
vadjustment |
GtkAdjustment |
Lecture/Ecriture |
allow-rules |
gboolean |
Lecture |
even-row-color |
GdkColor |
Lecture |
expander-size |
gint |
Lecture |
horizontal-separator |
gint |
Lecture |
indent-expanders |
gboolean |
Lecture |
odd-row-color |
GdkColor |
Lecture |
vertical-separator |
gint |
Lecture |
GtkTreeViewColumn
Propriété |
Type |
Accès |
---|---|---|
alignment |
gfloat |
Lecture/Ecriture |
clickable |
gboolean |
Lecture/Ecriture |
fixed-width |
gint |
Lecture/Ecriture |
max-width |
gint |
Lecture/Ecriture |
min-width |
gint |
Lecture/Ecriture |
reorderable |
gboolean |
Lecture/Ecriture |
resizable |
gboolean |
Lecture/Ecriture |
sizing |
GtkTreeViewColumnSizing |
Lecture/Ecriture |
sort-indicator |
gboolean |
Lecture/Ecriture |
sort-order |
GtkSortType |
Lecture/Ecriture |
title |
gchararray |
Lecture/Ecriture |
visible |
gboolean |
Lecture/Ecriture |
widget |
GtkWidget |
Lecture/Ecriture |
width |
gint |
Lecture |
GtkCellRenderer
Propriété |
Type |
Accès |
---|---|---|
cell-background |
gchararray |
Ecriture |
cell-background-gdk |
GdkColor |
Lecture/Ecriture |
cell-background-set |
gboolean |
Lecture/Ecriture |
height |
gint |
Lecture/Ecriture |
is-expanded |
gboolean |
Lecture/Ecriture |
is-expander |
gboolean |
Lecture/Ecriture |
mode |
GtkCellRendererMode |
Lecture/Ecriture |
visible |
gboolean |
Lecture/Ecriture |
width |
gint |
Lecture/Ecriture |
xalign |
gfloat |
Lecture/Ecriture |
xpad |
guint |
Lecture/Ecriture |
yalign |
gfloat |
Lecture/Ecriture |
ypad |
guint |
Lecture/Ecriture |
GtkCellRenderText
Propriété |
Type |
Accès |
---|---|---|
attributes |
PangoAttrList |
Lecture/Ecriture |
background |
gchararray |
Ecriture |
background-gdk |
GdkColor |
Lecture/Ecriture |
background-set |
gboolean |
Lecture/Ecriture |
editable |
gboolean |
Lecture/Ecriture |
editable-set |
gboolean |
Lecture/Ecriture |
family |
gchararray |
Lecture/Ecriture |
family-set |
gboolean |
Lecture/Ecriture |
font |
gchararray |
Lecture/Ecriture |
font-desc |
PangoFontDescription |
Lecture/Ecriture |
foreground |
gchararray |
Ecriture |
foreground-gdk |
GdkColor |
Lecture/Ecriture |
foreground-set |
gboolean |
Lecture/Ecriture |
markup |
gchararray |
Ecriture |
rise |
gint |
Lecture/Ecriture |
rise-set |
gboolean |
Lecture/Ecriture |
scale |
gdouble |
Lecture/Ecriture |
scale-set |
gboolean |
Lecture/Ecriture |
size |
gint |
Lecture/Ecriture |
size-points |
gdouble |
Lecture/Ecriture |
size-set |
gboolean |
Lecture/Ecriture |
stretch |
PangoStretch |
Lecture/Ecriture |
stretch-set |
gboolean |
Lecture/Ecriture |
strikethrough |
gboolean |
Lecture/Ecriture |
strikethrough-set |
gboolean |
Lecture/Ecriture |
style |
PangoStyle |
Lecture/Ecriture |
style-set |
gboolean |
Lecture/Ecriture |
text |
gchararray |
Lecture/Ecriture |
underline |
PangoUnderline |
Lecture/Ecriture |
underline-set |
gboolean |
Lecture/Ecriture |
variant |
PangoVariant |
Lecture/Ecriture |
variant-set |
gboolean |
Lecture/Ecriture |
weight |
gint |
Lecture/Ecriture |
weight-set |
gboolean |
Lecture/Ecriture |
GtkCellRendererToggle
Propriété |
Type |
Accès |
---|---|---|
activatable |
gboolean |
Lecture/Ecriture |
active |
gboolean |
Lecture/Ecriture |
inconsistent |
gboolean |
Lecture/Ecriture |
radio |
gboolean |
Lecture/Ecriture |
GtkCellRenderPixbuf
Propriété |
Type |
Accès |
---|---|---|
pixbuf |
GdkPixbuf |
Lecture/Ecriture |
pixbuf-expander-closed |
GdkPixbuf |
Lecture/Ecriture |
pixbuf-expander-open |
GdkPixbuf |
Lecture/Ecriture |
stock-detail |
gchararray |
Lecture/Ecriture |
stock-id |
gchararray |
Lecture/Ecriture |
stock-size |
GtkIconSize |
Lecture/Ecriture |
XXIII-E-2. Les signaux▲
Prototypes fonctions callback :
GtkTreeView
-
columns-changed
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, gpointer user_data); -
cursor-changed
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, gpointer user_data); -
expand-collapse-cursor-row
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gboolean arg1, gboolean arg2, gboolean arg3, gpointer user_data); -
move-cursor
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, GtkMovementStep arg1, gint arg2, gpointer user_data); -
row-activated
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, GtkTreePath*
arg1, GtkTreeViewColumn*
arg2, gpointer user_data); -
row-collapsed
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, GtkTreeIter*
arg1, GtkTreePath*
arg2, gpointer user_data); -
row-expanded
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, GtkTreeIter*
arg1, GtkTreePath*
arg2, gpointer user_data); -
select-all
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gpointer user_data); -
select-cursor-parent
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gpointer user_data); -
select-cursor-row
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gboolean arg1, gpointer user_data); -
set-scroll-adjustments
Sélectionnezvoid
user_function
(
GtkTreeView*
treeview, GtkAdjustment*
arg1, GtkAdjustment*
arg2, gpointer user_data); -
start-interactive-search
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gpointer user_data); -
test-collapse-row
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, GtkTreeIter*
arg1, GtkTreePath*
arg2, gpointer user_data); -
test-expand-row
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, GtkTreeIter*
arg1, GtkTreePath*
arg2, gpointer user_data); -
toggle-cursor-row
Sélectionnezgboolean
user_function
(
GtkTreeView*
treeview, gpointer user_data); - unselect-all
gboolean user_function
(
GtkTreeView *
treeview, gpointer user_data);
GtkTreeViewColumn
- clicked
void
user_function
(
GtkTreeViewColumn *
treeviewcolumn, gpointer user_data);
GtkCellRendererText
- edited
void
user_function
(
GtkCellRendererText *
cellrenderertext, gchar *
arg1, gchar *
arg2, gpointer user_data);
GtkCellRendererToggle
- toggled
void
user_function
(
GtkCellRendererToggle *
cellrenderertoggle, gchar *
arg1, gpointer user_data);
XXIV. Copyright▲
Copyright (c) 2002-2003 Equipe GTK-FR.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled « Licence ».
XXV. Licence▲
GNU Free Documentation License
Version 1.1, March 2000
Copyright (C) 2000 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
XXV-A. PREAMBLE▲
The purpose of this License is to make a manual, textbook, or other written document « free » in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.
This License is a kind of « copyleft », which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.
We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.
XXV-B. APPLICABILITY AND DEFINITIONS▲
This License applies to any manual or other work that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. The « Document », below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as « you ».
A « Modified Version » of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.
A « Secondary Section » is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (For example, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.
The « Invariant Sections » are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License.
The « Cover Texts » are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License.
A « Transparent » copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, whose contents can be viewed and edited directly and straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup has been designed to thwart or discourage subsequent modification by readers is not Transparent. A copy that is not « Transparent » is called « Opaque ».
Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML designed for human modification. Opaque formats include PostScript, PDF, proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML produced by some word processors for output purposes only.
The « Title Page » means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, « Title Page » means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.
XXV-C. VERBATIM COPYING▲
You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and you may publicly display copies.
XXV-D. COPYING IN QUANTITY▲
If you publish printed copies of the Document numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.
If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.
If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a publicly-accessible computer-network location containing a complete Transparent copy of the Document, free of added material, which the general network-using public has access to download anonymously at no charge using public-standard network protocols. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.
It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.
XXV-E. MODIFICATIONS▲
You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:
A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has less than five).
C. State on the Title page the name of the publisher of the Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section entitled « History », and its title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section entitled « History » in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the « History » section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
K. In any section entitled « Acknowledgements » or « Dedications », preserve the section's title, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
M. Delete any section entitled « Endorsements ». Such a section may not be included in the Modified Version.
N. Do not retitle any existing section as « Endorsements » or to conflict in title with any Invariant Section.
If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.
You may add a section entitled « Endorsements », provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.
You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.
The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.
XXV-F. COMBINING DOCUMENTS▲
You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice.
The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.
In the combination, you must combine any sections entitled « History » in the various original documents, forming one section entitled « History »; likewise combine any sections entitled « Acknowledgements », and any sections entitled « Dedications ». You must delete all sections entitled « Endorsements. »
XXV-G. COLLECTIONS OF DOCUMENTS▲
You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.
You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.
XXV-H. AGGREGATION WITH INDEPENDENT WORKS▲
A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, does not as a whole count as a Modified Version of the Document, provided no compilation copyright is claimed for the compilation. Such a compilation is called an « aggregate », and this License does not apply to the other self-contained works thus compiled with the Document, on account of their being thus compiled, if they are not themselves derivative works of the Document.
If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one quarter of the entire aggregate, the Document's Cover Texts may be placed on covers that surround only the Document within the aggregate. Otherwise they must appear on covers around the whole aggregate.
XXV-I. TRANSLATION▲
Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License provided that you also include the original English version of this License. In case of a disagreement between the translation and the original English version of this License, the original English version will prevail.
XXV-J. TERMINATION▲
You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
XXV-K. FUTURE REVISIONS OF THIS LICENSE▲
The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License « or any later version » applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation.
XXVI. Historique▲
19 décembre 2003 - Version 1.4
Nouveaux chapitres :
- Les tables
- Les pages à onglets
- Le widget GtkTreeView
21 mai 2003 - Version 1.2
Nouveaux chapitres :
- La barre d'outils
- La sélection de valeurs numériques
- La barre de progression
Mise à jour des chapitres :
- Les labels
- Les décorations
- Les images
- Les boites de dialogue
- La barre d'état
8 février 2003 - Version 1.1.2
Mise à jour des chapitres :
- Les labels
- Les boutons (Partie 1)
- Les box
- Les entrées de saisie
- Les boites de dialogue
Ajout d'un chapitre :
- Les décorations
25 janvier 2003 - Version 1.1.1
Corrections de fautes d'orthographe.
17 novembre 2002 - Version 1.1
Mise à jour des chapitres :
- Introduction
- Premier programme
- Les fenêtres
Ajout des chapitres
- Sélection des fichiers
- Les fenêtres avec barres de défilement
- Les zones de texte
- La barre d'état
- Les images
23 septembre 2002 - Version 1.0
Contenu du cours :
- Présentation
- Premier programme
- Les fenêtres
- Les labels
- Les boutons (partie 1)
- Les box
- Les listes chaînées
- Les entrées de saisie
- Les boites de dialogue
- Les menus
- Les boutons (partie 2)