doc

Transcription

doc
GTK+
Langages, outils et méthodes pour la programmation avancée
14 décembre 2003
version 1.0
ANDRIANJAFY - MBAYE
Enseignant: Françoise Balmas
Table des matières
1 Qu’est-ce que c’est que GTK+ ?
2
2 Installation et compilation
2.1 Installation de GTK+ . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Compiler un programme GTK+ . . . . . . . . . . . . . . . . . .
3
3
3
3 Créer une application GTK+
3.1 Créer une fenêtre . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Affichage de la fenêtre . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Les signaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
5
6
6
4 Quelques widgets
4.1 Les Box . . . . . . . . . . . . . . . . . . . . .
4.1.1 Création . . . . . . . . . . . . . . . . .
4.1.2 Insérer un widget dans un box . . . .
4.2 Les boutons . . . . . . . . . . . . . . . . . . .
4.2.1 Création du bouton . . . . . . . . . .
4.2.2 Action et affichage . . . . . . . . . . .
4.3 Sélection de fichiers . . . . . . . . . . . . . . .
4.3.1 Créer et afficher le widget . . . . . . .
4.3.2 Récupérer le chemin . . . . . . . . . .
4.4 La zone de texte . . . . . . . . . . . . . . . .
4.4.1 Créer et afficher un GtkTextView . . .
4.4.2 Accéder au contenu de GtkTextBuffer
5 Un
5.1
5.2
5.3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
9
9
10
10
11
11
11
11
12
13
13
programme complet
15
L’éditeur de texte . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Code source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Aperçu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1
Chapitre 1
Qu’est-ce que c’est que
GTK+ ?
GTK+1 est une bibliothèque C permettant de créer des interfaces graphiques
utilisateur (GUI) très facilement. A l’origine, GTK+ a été développé pour les
besoins du logiciel de traitement d’images GIMP (GNU Image Manipulation
Program). Aujourd’hui, le domaine d’application ne se limite plus seulement à
GIMP, mais à 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. Ainsi,GTK+ est une bibliothèque
libre ; il est donc possible de l’utiliser ou de la modifier sans aucune
contrainte financière.
– GTK+ est portable : il fonctionne sur les plates-formes UNIX, Linux,
Windows, BeOs.
– GTK+ est utilisable avec plusieurs langages de programmation. Même
si les créateurs de GTK+ ont écris cette bibliothèque en C, sa structure
orientée objets et sa licence ont permis à d’autres développeurs d’adapter
GTK+ à d’autres langages. Ainsi, il est maintenant possible de programmer des GUI GTK+ en C, C++, Ada, Perl, Python, PHP et bien d’autres.
1 Le
site officiel de GTK+ est http ://www.gtk.org.
2
Chapitre 2
Installation et compilation
2.1
Installation de GTK+
Il faut savoir que GTK+ s’appuie sur plusieurs bibliothèques et que donc, il
faut absolument les installer avant de pouvoir utiliser GTK+.
Sous Linux, votre distribution inclue 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 ne possédez pas la version 2 de GTK+, téléchargez les fichiers
sources de la version la plus récente sur le site officiel de GTK+1 . 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
make install.
2.2
Compiler un programme GTK+
Afin de créer un executable GTK+, il est nécessaire de configurer l’éditeur
de lien en rajoutant des options dans la ligne de commande de compilation.
Avec gcc, il faudra rajouter l’option ‘pkg-config –cflags –libs gtk+-2.0‘ 2
Par exemple, si le code source se nomme MonProg.c, la ligne de commande
pour le compiler sera :
gcc MonProg.c -o MonProg ‘pkg-config --cflags --libs gtk+-2.0‘
1 Le
site ftp officiel est ftp ://ftp.gtk.org/pub/gtk/
ce sont des BACK QUOTES
2 Attention !
3
Chapitre 3
Créer une application
GTK+
La première chose à faire est d’ajouter le fichier en-tête au code source :
#include <gtk/gtk.h>
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 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é à une large
panoplie de fonctions permettant de manipuler ces objets. Parmi les objets
graphiques les plus courants, il y a :
– les fenêtres
– les boutons
– les zones de saisie
– les barres de menu
– ...etc...
Bien que GTK+ soit écrit en C, il introduit la notion d’héritage1 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. Voici un extrait de la hiérachie des objets GTK+ :
1 concept
fondamental de la Programmation Orientée Objet
4
Fig. 3.1 –
3.1
Extrait de la hiérachie des objets GTK+
Créer une fenêtre
Le widget permettant d’afficher une fenêtre, le premier élément d’une interface qraphique, 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.
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 *fenetre;
Par la suite, quel que soit l’objet à créer, il faudra toujours déclarer un
GtkWidget. Une fois l’objet pWindow déclarer, il faut l’initialiser. Pour cela,
une fonction est à notre disposition :
GtkWidget* gtk_window_new(GtkWindowType type);
Le paramètre type définit le type de la fenêtre en cours de création, et peut
prendre une des deux valeurs suivantes :
– GTK WINDOW TOPLEVEL : pour créer une fenêtre complète avec
une zone réservée dans la barre des tâches ;
– GTK WINDOW POPUP : pour créer une fenêtre sans aucune décoration
(barre de titre, bordure, ...).
La valeur de retour est le pointeur sur notre nouvel objet fenêtre. Cette fonction
est donc à utiliser comme ceci :
5
fenetre = gtk_window_new(GTK_WINDOW_TOPLEVEL);
La création de la fenêtre est maintenant terminée.
3.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(fenetre);
Au contraire, pour détruire la fenêtre, la fonction sera :
void gtk_widget_destroy(GtkWidget *widget);
Le code source d’un exemple complet est disponible à la fin de ce chapitre.
3.3
Les signaux
Pour faire réagir une application GTK+ aux actions de l’utilisateur, nous
avons besoin d’utiliser les signaux.
Dans un premier temps, lorsque l’utilisateur interagie avec l’application
(clique sur un bouton, ferme une fenêtre, ...), le widget concerné émet un signal,
par exemple ”destroy” lorsque l’on ferme une fenêtre. Chaque widget est associé
à un ou plusieurs signaux et permet donc ainsi de programmer toutes les actions
possibles. Ce signal va ensuite être intercepté par une boucle évènementielle qui
va vérifier qu’une action spécifique à ce signal et à ce widget a bien été définie.
Si tel est le cas, la fonction associée sera exécutée. Ce type de fonction s’appelle fonction callback. Il faut donc créer une fonction callback pour chacun
des évènements susceptible d’avoir lieu pendant l’exécution du programme et
associer (ou connecter) cette fonction à un signal.
La première étape consiste donc à créer une fonction callback. Dans la majorité des cas, une fonction callback sera de cette forme :
void nom_de_la_fonction(GtkWidget *widget, gpointer data)
Le paramètre widget est le widget qui a émis le signal, et data est une donnée
supplémentaire qui peut être utilisée.
Ensuite, pour connecter un signal à une fonction callback, GTK+ utilise une
fonction de la bibliothèque GLib qui est :
gulong g_signal_connect(gpointer *object, const gchar *name,
GCallback func, gpointer func_data );
Le premier paramètre object, correspond au widget qui émet le signal. Cependant, la variable demandée par g signal connect étant de type gpointer*
(correspond à void* du C standard) et le widget de type GtkWidget*, il faut
6
convertir ce dernier pour ne pas provoquer d’erreur lors de la compilation. Pour
cela GTK+ fourni une macro de conversion (G OBJECT) qui sera à utiliser à
chaque utilisation de cette fonction.
Le second paramètre name, est le signal qui doit être intercepter par la boucle
évènementielle.
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.
7
Voici le code source complet d’une application affichant une fenêtre et supportant les signaux.
#include <stdlib.h>
#include <gtk/gtk.h>
void OnDestroy(GtkWidget *pWidget, gpointer pData)
{
/* Arret de la boucle evenementielle */
gtk_main_quit();
}
int main(int argc,char **argv)
{
/* Declaration du widget */
GtkWidget *fenetre;
gtk_init(&argc,&argv);
/* Creation de la fenetre */
fenetre = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/* Connexion du signal "destroy" */
g_signal_connect(G_OBJECT(fenetre), "destroy",
G_CALLBACK(OnDestroy), NULL);
/* Affichage de la fenetre */
gtk_widget_show(fenetre);
/* Demarrage de la boucle evenementielle */
gtk_main();
return EXIT_SUCCESS;
}
Fig. 3.2 –
Fenêtre gérant les signaux
8
Chapitre 4
Quelques widgets
4.1
Les Box
Dans GTK+, il est impossible de mettre plusieurs widgets dans une fenêtre.
Cela est dû au fait qu’un widget de type GtkContainer ne peut contenir qu’un
seul widget. Afin de disposer les widgets et mettre en page une fenêtre, GTK+
propose alors d’utiliser des widgets de type GtkBox qui permettent d’inclure
plusieurs widgets à l’intérieur de celui-ci.
Il existe deux types de GtkBox :
– les GtkHBox qui permettent de disposer les widgets horizontalement
– les GtkVBox pour les disposer verticalement
4.1.1
Création
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.
4.1.2
Insérer un widget dans un box
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);
9
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.
Voici la signification des différents paramètres :
– box : la GtkBox dans laquelle on veut insérer le widget child (2ème paramètre)
– expand : n’est utile que si la GtkBox en question n’est pas défini 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.
– fill : définit si le widget enfant occupe toute la zone qui lui est réservée.
– padding : ajoute 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).
4.2
Les boutons
Le bouton fait parti des éléments essentiels d’une interface graphique. En
effet celui-ci permet à l’utilisateur d’effectuer une action grâce à un simple click
de souris. GTK+ nous permet de les utiliser grâce au widget GtkButton.
4.2.1
Création du bouton
Dans un premier temps, il faut déclarer un pointeur vers une structure GtkWidget afin de pouvoir ensuite créer le bouton.
GtkWidget *bouton_quitter;
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_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.
La troisième fonction permet de créer un bouton avec un label, un raccourci
clavier et une image. Pour faire cela, GTK+ utilise les GtkStockItem qui
est une structure contenant les informations sur le label et l’image à afficher.
GTK+ comporte beaucoup de GtkStockItem prédéfinis. Le paramètre stock id
est donc l’identifiant du GtkStockItem à utiliser : par exemple, le stock id
GTK STOCK QUIT affiche une image représentant une porte ouverte (sortie)
dans le bouton, à côté du label.
10
4.2.2
Action et affichage
Il reste ensuite à définir l’action qui sera lier avec 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, par exemple et détruire tous les widgets. La ligne de code
est donc :
g_signal_connect(G_OBJECT(bouton_quitter), "clicked",
G_CALLBACK(gtk_main_quit), NULL);
Enfin, pour que le bouton soit visible, il faut l’afficher dans la fenêtre. On
utilise la fonction gtk container add pour insérer le bouton dans la fenêtre et
gtk widget show all pour afficher tous les widgets.
4.3
Sélection de fichiers
Le widget GtkFileSelection, comme son nom l’indique, est une boı̂te de
dialogue qui permet de demander à l’utilisateur le chemin d’un fichier particulier,
à travers une liste de répertoire et de fichiers.
4.3.1
Créer et afficher le widget
On crée tout d’abord un pointeur vers la structure GtkWidget.
GtkWidget* file_selection;
On va ensuite 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 boı̂te de dialogue : vous pouvez
ainsi l’appeler suivant vos besoins ”ouvrir...”, ”selectionner un fichier...”, etc..
Enfin pour l’afficher, on utilisera la fonction :
gtk_window_show(file_selection);
4.3.2
Récupérer le chemin
Afin de récupérer le chemin spécifié par l’utilisateur lorsque celui-ci appuie
sur le bouton ok, on va 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. Voila la
fonction qui permet d’obtenir le chemin du fichier ou du répertoire sélectionné
à partir de la gtk file selection :
11
G_CONST_RETURN gchar* gtk_file_selection_get_filename
(GtkFileSelection *filesel);
Voici un exemple de fonction qui récupère dans une chaine de caractère le
chemin retourné par un widget GtkFileSelection :
void recuperer_chemin(GtkWidget *bouton,GtkWidget *file_selection)
{
gchar *chemin;
chemin = gtk_file_selection_get_filename
(GTK_FILE_SELECTION (file_selection) );
}
Fig. 4.1 –
4.4
Exemple de fenêtre de sélection de fichier sous GTK+
La zone de texte
Afin de pouvoir saisir plusieurs lignes de texte, 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 pour le manipuler.
12
4.4.1
Créer et afficher un GtkTextView
Il faut déjà 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.
Il faut maintenant insérer text view dans la box.
gtk_box_pack_start(GTK_BOX(box),text_view,TRUE,TRUE,0);
4.4.2
Accéder au contenu de GtkTextBuffer
Tout d’abord, il faut récupérer l’adresse du buffer GtkTextBuffer, 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));
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)
Ces paramètres sont :
– buffer : le nom du buffer sur lequel on veut agir
– 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 : inclure ou non les caractères cachées, mettre à false
– valeur retournée : une chaı̂ne de caractère de type C et allouée dans le tas
Le deuxième et le troisième paramètre sont en fait une partie du buffer : ils
indiquent la position de début et de fin de la chaı̂ne de caractère dans le buffer
à prendre en compte ; c’est une sous-chaı̂ne de caractère.
Pour se servir de l’itérateur GtkTextIter, il faut d’abord l’initialiser, en
déclarant des pointeurs comme on a l’habitude de le faire. Comme en général,
on veut 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 fonction
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);
13
A 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. 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);
Nous avons maintenant le contenu de text buffer copié dans buf. Maintenant,
on peut faire ce qu’on veut avec : 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);
14
Chapitre 5
Un programme complet
Pour illustrer la programmation avec la bibliothèque GTK+, voyons un
exemple de programme complet.
5.1
L’éditeur de texte
Ce programme est un éditeur de texte graphique. Il dispose des fonctionnalités suivantes :
– Nouveau : édite un nouveau texte
– Ouvrir : ouvre un fichier texte et l’affiche dans l’éditeur
– Enregister : sauvegarde le texte saisi dans un fichier
5.2
Code source
#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
static
static
static
static
void
void
void
void
void
void
GtkWidget *texte;
GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter end;
OnDestroy(GtkWidget *pWidget, gpointer pData);
OnNew(GtkWidget *pWidget, gpointer pData);
OnOpen(GtkButton *bouton);
OnSave(GtkButton *bouton);
ouvrir_fichier(GtkWidget *bouton, GtkWidget *file_selection);
save_fichier(GtkWidget *bouton, GtkWidget *file_selection);
/* Definition des elements du menu */
static GtkItemFactoryEntry MenuItem[] = {
{ "/_Fichier", NULL, NULL, 0, "<Branch>" },
{ "/Fichier/_Nouveau","<ctrl>N",OnNew, 0, "<StockItem>",
GTK_STOCK_NEW },
15
{ "/Fichier/_Ouvrir", "<ctrl>O", OnOpen, 0, "<StockItem>",
GTK_STOCK_OPEN },
{ "/Fichier/Enregi_strer", "<ctrl>S", OnSave, 0, "<StockItem>",
GTK_STOCK_SAVE },
{ "/Fichier/Sep1", NULL, NULL, 0, "<Separator>" },
{ "/Fichier/_Quitter", NULL, OnDestroy, 1, "<StockItem>",
GTK_STOCK_QUIT},
};
/* Nombre d elements du menu */
static gint iNbMenuItem = sizeof(MenuItem) / sizeof(MenuItem[0]);
/*evenement: destruction d’un widget*/
/*************************************/
void OnDestroy(GtkWidget *pWidget, gpointer pData)
{
/* Arret de la boucle evenementielle */
gtk_main_quit();
}
/*evenement: creation de document*/
/*********************************/
void OnNew(GtkWidget *pWidget, gpointer pData)
{
/*vide le contenu du buffer*/
if (buffer!=NULL) {
gtk_text_buffer_get_start_iter(buffer,&start);
gtk_text_buffer_get_end_iter(buffer,&end);
gtk_text_buffer_delete(buffer, &start, &end);
}
}
/*evenement: ouverture fichier*/
/******************************/
void OnOpen(GtkButton *bouton)
{
GtkWidget *selection;
selection = gtk_file_selection_new("Selectionner un fichier");
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);
16
}
/*evenement: enregistrement fichier*/
/***********************************/
void OnSave(GtkButton *bouton)
{
GtkWidget *selection;
selection = gtk_file_selection_new("Ecrire un fichier");
gtk_widget_show(selection);
g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(selection)->ok_button),
"clicked", G_CALLBACK(save_fichier), selection );
g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(selection)->cancel_button),
"clicked", G_CALLBACK(gtk_widget_destroy), selection);
}
/*procedure d’ouverture de fichier*/
/**********************************/
void ouvrir_fichier(GtkWidget *bouton, GtkWidget *file_selection)
{
FILE *fichier;
const gchar *chemin;
gchar lecture[1024];
/*recupère le buffer de ’texte’*/
buffer=gtk_text_view_get_buffer(GTK_TEXT_VIEW(texte));
/*recupere le chemin du fichier qu’on a selectioné*/
chemin=gtk_file_selection_get_filename(GTK_FILE_SELECTION (file_selection));
fichier = fopen(chemin,"rt"); /*ouvre le fichier*/
/*message d’erreur*/
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);/*supprime la boite de selection*/
17
gtk_text_buffer_get_start_iter(buffer,&start);
gtk_text_buffer_get_end_iter(buffer,&end);
gtk_text_buffer_delete(buffer, &start, &end);/*supprime le contenu du buffer*/
/*lit le contenu du fichier et le met dans 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);
}
fclose(fichier);
}
/*procedure d’enregistrement de fichier*/
/***************************************/
void save_fichier(GtkWidget *bouton, GtkWidget *file_selection)
{
FILE *fichier;
const gchar *chemin;
gchar *ecriture=0;
/*on recupere le buffer*/
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(texte));
chemin = gtk_file_selection_get_filename(GTK_FILE_SELECTION (file_selection));
fichier = fopen(chemin,"wt");
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’ecrire dans 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);
/*on recupere l’origine du buffer*/
gtk_text_buffer_get_start_iter(buffer,&start);
/*on recupere la fin du buffer*/
gtk_text_buffer_get_end_iter(buffer,&end);
/*recupere dans ’ecriture’ le conteu du buffer*/
ecriture=gtk_text_buffer_get_text(buffer,&start, &end,TRUE);
fputs(ecriture,fichier); /*ecrit le contenu de ’ecriture’ dans le fichier*/
18
fclose(fichier);
}
int main(int argc, char **argv)
{
/*déclaration des widgets*/
GtkWidget * fenetre;
GtkWidget * quitter;
GtkWidget * nouveau;
GtkWidget * ouvrir;
GtkWidget * panelV;
GtkWidget * barre;
GtkWidget * scrollbar;
GtkWidget * menu;
GtkItemFactory * item_factory;
GtkAccelGroup * raccourcis;
/*initialisation de GTK+*/
gtk_init(&argc, &argv);
/*création de tous les widgets*/
panelV = gtk_vbox_new(FALSE,0);
barre = gtk_toolbar_new();
fenetre = gtk_window_new(GTK_WINDOW_TOPLEVEL);
nouveau=gtk_button_new_from_stock(GTK_STOCK_NEW);
ouvrir=gtk_button_new_from_stock(GTK_STOCK_OPEN);
quitter=gtk_button_new_from_stock(GTK_STOCK_QUIT);
texte=gtk_text_view_new();
scrollbar=gtk_scrolled_window_new(NULL,NULL);
raccourcis=gtk_accel_group_new ();
item_factory=gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", raccourcis);
/*définit le titre de la fenetre*/
gtk_window_set_title(GTK_WINDOW(fenetre), "Editeur de texte");
/*affiche la fenetre au centre de l’ecran*/
gtk_window_set_position(GTK_WINDOW(fenetre),GTK_WIN_POS_CENTER);
/*definit la taille de la fenetre à 640x480*/
gtk_window_set_default_size(GTK_WINDOW(fenetre),640,480);
/*recuperation des elements du menu */
gtk_item_factory_create_items(item_factory, iNbMenuItem,
MenuItem, (GtkWidget*)fenetre);
/* Recuperation du widget pour l affichage du menu */
menu=gtk_item_factory_get_widget(item_factory, "<main>");
/*insere le panneau vertical à la fenetre principale*/
gtk_container_add(GTK_CONTAINER(fenetre),panelV);
19
/*insere la zone de texte(saisie) dans la barre de defilement*/
gtk_container_add(GTK_CONTAINER(scrollbar),texte);
/*insere la barre de menu en haut de la fenetre */
gtk_box_pack_start(GTK_BOX(panelV), menu, FALSE, FALSE, 0);
/*insere la barre d’outils dans le panneau vertical*/
gtk_box_pack_start(GTK_BOX(panelV),barre,FALSE,FALSE,0);
/*insere la barre de defilement dans le panneau verticale*/
gtk_box_pack_start(GTK_BOX(panelV),scrollbar,TRUE,TRUE,0);
/*association des raccourcis avec la fenetre */
gtk_window_add_accel_group(GTK_WINDOW(fenetre), raccourcis);
/*insertion du bouton nouveau*/
gtk_toolbar_insert_stock(GTK_TOOLBAR(barre),GTK_STOCK_NEW,"Nouveau",
NULL,G_CALLBACK(OnNew), NULL, -1);
/*insertion du bouton ouvrir*/
gtk_toolbar_insert_stock(GTK_TOOLBAR(barre),GTK_STOCK_OPEN,"Ouvrir",
NULL,G_CALLBACK(OnOpen), NULL, -1);
/*insertion du bouton enregistrer*/
gtk_toolbar_insert_stock(GTK_TOOLBAR(barre),GTK_STOCK_SAVE,"Enregistrer",
NULL,G_CALLBACK(OnSave), NULL, -1);
/*insertion du bouton quitter*/
gtk_toolbar_insert_stock(GTK_TOOLBAR(barre),GTK_STOCK_QUIT,"Quitter",
NULL,G_CALLBACK(OnDestroy), NULL, -1);
/*modification de la taille des icones */
gtk_toolbar_set_icon_size(GTK_TOOLBAR(barre),GTK_ICON_SIZE_BUTTON);
/* affichage uniquement des icones */
gtk_toolbar_set_style(GTK_TOOLBAR(barre),GTK_TOOLBAR_ICONS);
/*connexion du signal de fermeture de fenetre*/
g_signal_connect(G_OBJECT(fenetre), "destroy", G_CALLBACK(OnDestroy), NULL);
/*affiche touts les widgets*/
gtk_widget_show_all(fenetre);
/*demarrage de la boucle evenementielle*/
gtk_main();
return EXIT_SUCCESS;
}
20
5.3
Aperçu
Fig. 5.1 –
Fig. 5.2 –
Le menu fichier
La fenêtre de sélection de fichier
21

Documents pareils